forwardRef¶
forwardRef
позволяет вашему компоненту передать узел DOM родительскому компоненту с помощью ref.
1 |
|
Описание¶
forwardRef(render)
¶
Вызовите forwardRef()
, чтобы позволить вашему компоненту получить ссылку и переслать ее дочернему компоненту:
1 2 3 4 5 |
|
Параметры
render
: Функция рендеринга для вашего компонента. React вызывает эту функцию с props иref
, которые ваш компонент получил от своего родителя. JSX, который вы возвращаете, будет выходом вашего компонента.
Возвращает
forwardRef
возвращает React-компонент, который вы можете отобразить в JSX. В отличие от компонентов React, определяемых как простые функции, компонент, возвращаемый forwardRef
, также может принимать пропс ref
.
Предостережения
- В строгом режиме React будет вызывать вашу функцию рендеринга дважды, чтобы помочь вам найти случайные примеси. Это поведение только для разработчиков и не влияет на производство. Если ваша функция рендеринга чиста (как и должно быть), это не должно повлиять на логику вашего компонента. Результат одного из вызовов будет проигнорирован.
render
функция¶
forwardRef
принимает функцию рендеринга в качестве аргумента. React вызывает эту функцию с props
и ref
:
1 2 3 4 5 6 7 8 |
|
Параметры
props
: Пропсы, переданные родительским компонентом.ref
: Атрибутref
, переданный родительским компонентом. Атрибутref
может быть объектом или функцией. Если родительский компонент не передал атрибут ref, он будетnull
. Вы должны либо передать полученныйref
другому компоненту, либо передать его вuseImperativeHandle
.
Возвращает
forwardRef
возвращает React-компонент, который вы можете отобразить в JSX. В отличие от компонентов React, определенных как простые функции, компонент, возвращаемый forwardRef
, может принимать пропс ref
.
Использование¶
Раскрытие узла DOM для родительского компонента¶
По умолчанию DOM-узлы каждого компонента являются приватными. Однако иногда полезно раскрыть узел DOM для родительского компонента - например, чтобы разрешить его фокусировку. Чтобы сделать это, оберните определение вашего компонента в forwardRef()
:
1 2 3 4 5 6 7 8 9 10 11 |
|
Вы получите ref
в качестве второго аргумента после props
. Передайте его узлу DOM, который вы хотите раскрыть:
1 2 3 4 5 6 7 8 9 10 11 |
|
Это позволяет родительскому компоненту Form
получить доступ к DOM-узлу <input>
, открытому MyInput
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
Этот компонент Form
передает ссылку в MyInput
. Компонент MyInput
передает эту ссылку в тег браузера input
. В результате компонент Form
может получить доступ к узлу DOM input
и вызвать focus()
для него.
Помните, что раскрытие ссылки на узел DOM внутри вашего компонента усложняет последующее изменение внутреннего устройства компонента. Обычно вы будете раскрывать узлы DOM из многократно используемых низкоуровневых компонентов, таких как кнопки или текстовые входы, но вы не будете делать этого для компонентов прикладного уровня, таких как аватар или комментарий.
Примеры пересылки реферера¶
1. Фокусировка текстового ввода
При нажатии на кнопку происходит фокусировка ввода. Компонент Form
определяет ссылку и передает ее компоненту MyInput
. Компонент MyInput
передает эту ссылку браузеру input
. Это позволяет компоненту Form
сфокусировать ввод
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
2. Воспроизведение и приостановка видео
Нажатие на кнопку вызывает play()
и pause()
на DOM-узле <video>
. Компонент App
определяет ссылку и передает ее компоненту MyVideoPlayer
. Компонент MyVideoPlayer
пересылает ссылку на узел <video>
браузера. Это позволяет компоненту App
воспроизводить и приостанавливать <video>
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
Пересылка ссылки через несколько компонентов¶
Вместо пересылки ref
на узел DOM, вы можете переслать его на свой собственный компонент, например MyInput
:
1 2 3 4 5 6 7 8 9 10 11 12 |
|
Если компонент MyInput
передает ссылку на свой <input>
, ссылка на FormField
даст вам этот <input>
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
|
Компонент Form
определяет ссылку и передает ее в FormField
. Компонент FormField
передает эту ссылку в MyInput
, который передает ее в DOM-узел браузера input
. Вот как Form
получает доступ к этому DOM-узлу.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
Выставление императивного дескриптора вместо узла DOM¶
Вместо того чтобы раскрывать весь узел DOM, вы можете раскрыть пользовательский объект, называемый императивным дескриптором, с более ограниченным набором методов. Для этого вам нужно определить отдельный ref для хранения DOM-узла:
1 2 3 4 5 6 7 |
|
Передайте полученный ref
в useImperativeHandle
и укажите значение, которое вы хотите передать ref
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
|
Если какой-то компонент получит ссылку на MyInput
, он получит только ваш объект { focus, scrollIntoView }
вместо узла DOM. Это позволяет вам ограничить информацию о вашем узле DOM до минимума.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
|
Подробнее об использовании императивных дескрипторов
Не злоупотребляйте ссылками
Ссылки следует использовать только для императивного поведения, которое вы не можете выразить как пропс: например, прокрутка к узлу, фокусировка узла, запуск анимации, выделение текста и так далее.
Если вы можете выразить что-то как пропс, вы не должны использовать ссылку. Например, вместо того, чтобы раскрывать императивный дескриптор типа { open, close }
из компонента Modal
, лучше взять isOpen
как пропс, например <Modal isOpen={isOpen} />
. Effects может помочь вам раскрыть императивное поведение через пропсы.
Устранение неполадок¶
Мой компонент обернут в forwardRef
, но ref
на него всегда null
¶
Обычно это означает, что вы забыли использовать полученный ref
.
Например, этот компонент ничего не делает со своим ref
:
1 2 3 4 5 6 7 8 9 10 11 |
|
Чтобы исправить это, передайте ref
вниз к узлу DOM или другому компоненту, который может принимать ссылку:
1 2 3 4 5 6 7 8 9 10 11 |
|
Ссылка ref
на MyInput
может также быть null
, если некоторая логика является условной:
1 2 3 4 5 6 7 8 9 10 11 |
|
Если showInput
будет false
, то ссылка не будет перенаправлена ни на какой узел, и ссылка на MyInput
останется пустой. Это особенно легко пропустить, если условие скрыто внутри другого компонента, как Panel
в этом примере:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
Источник — https://react.dev/reference/react/forwardRef