Перенаправление рефов¶
Перенаправление рефов позволяет автоматически передавать реф компонента одному из его дочерних элементов. Большинству компонентов перенаправление рефов не нужно, но оно может быть полезно, например, если вы пишете библиотеку. Рассмотрим наиболее частые сценарии.
Перенаправление рефов в DOM-компоненты¶
Допустим, у нас есть компонент FancyButton
, который рендерит нативный DOM-элемент button
:
1 2 3 4 5 6 7 |
|
React-компоненты скрывают свои детали реализации, в том числе результат рендеринга. Реф элемента button
из FancyButton
обычно и не требуется другим компонентам. Это хорошо, поскольку такой подход не даёт компонентам излишне полагаться на структуру DOM друг друга.
Такая инкапсуляция хорошо подходит компонентам, которые описывают некую законченную часть приложения, например, FeedStory
или Comment
. А вот в «маленьких», часто повторно используемых компонентах, таких как FancyButton
или MyTextInput
, она может быть неудобной. Чтобы управлять фокусом, выделением и анимациями этих компонентов, придётся получить доступ к их DOM-узлам.
Перенаправление рефов позволяет взять ref
из атрибутов компонента, и передать («перенаправить») его одному из дочерних компонентов.
В данном примере мы используем React.forwardRef
в компоненте FancyButton
, чтобы получить реф и передать его в дочерний DOM-элемент button
.
1 2 3 4 5 6 7 8 9 10 |
|
Таким образом, когда мы будем применять FancyButton
в других компонентах, мы сможем получить реф находящегося в нём DOM-узла button
и использовать его так же, как если бы мы рендерили непосредственно button
.
Рассмотрим этот пример пошагово:
- Мы создаём реф, вызвав
React.createRef
и записываем его в переменнуюref
. - Мы передаём переменную
ref
в<FancyButton ref={ref}>
, указывая её в JSX-атрибуте. - React передаёт
ref
в функцию(props, ref) => ...
внутриforwardRef
в качестве второго аргумента. - Мы передаём аргумент
ref
дальше в<button ref={ref}>
, указывая его в JSX-атрибуте. - После привязки рефа
ref.current
будет указывать на DOM-узел<button>
.
Примечание
Второй аргумент
ref
существует только в том случае, если вы создаёте компонент через функциюReact.forwardRef
. Обычные функциональные или классовые компоненты не получаютref
в качестве аргумента или пропа.Перенаправить реф можно не только в DOM-компонент, но и в экземпляр классового компонента.
Примечание для разработчиков библиотек компонентов¶
Если вы впервые использовали forwardRef
в компоненте библиотеки, то следует сделать новую версию мажорной и указать на обратную несовместимость изменений. Причина этого в том, что, скорее всего, компонент станет вести себя заметно иначе (например, изменится тип экспортируемых данных и элемент, к которому привязан реф), в результате чего приложения и другие библиотеки, полагающиеся на старое поведение, перестанут работать.
По этой же причине мы рекомендуем не вызывать React.forwardRef
условно (то есть сперва проверяя, что эта функция определена). Это изменит поведение вашей библиотеки и приложения ваших пользователей могут перестать работать при обновлении самого React.
Перенаправление рефов в компонентах высшего порядка¶
Особенно полезным перенаправление может оказаться в компонентах высшего порядка (также известных как HOC). Начнём с примера, в котором HOC выводит пропсы компонента в консоль:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
Компонент высшего порядка logProps
передаёт все пропсы в компонент, который он оборачивает, так что рендерить они будут одно и то же. С его помощью мы будем выводить в консоль все пропсы, переданные в наш компонент с кнопкой:
1 2 3 4 5 6 7 8 9 10 11 12 |
|
Обратите внимание, что в этом примере не будут передаваться рефы. Так происходит, потому что ref
это не проп. Подобно key
, React обрабатывает ref
особым образом. Если вы укажите реф для HOC, он привяжется к ближайшему к корню контейнера, а не к переданному в HOC компоненту.
Следовательно, рефы, предназначенные для компонента FancyButton
, окажутся привязанными к компоненту LogProps
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
К счастью, мы можем явно перенаправить рефы на компонент FancyButton
внутри HOC при помощи API React.forwardRef
. В React.forwardRef
передаётся функция рендеринга, которая принимает аргументы props
и ref
, а возвращает узел React. Например:
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 |
|
Изменение названия в инструментах разработки¶
В React.forwardRef
передаётся функция рендеринга. Эта функция определяет, как будет называться компонент в инструментах разработки.
Например, вот этот компонент будет называться «ForwardRef»:
1 2 3 |
|
Если присвоить имя функции рендеринга, то оно появится в названии компонента в инструментах разработки (например, «ForwardRef(myFunction)»):
1 2 3 4 5 |
|
Можно даже назначить функции свойство displayName
и указать в нём, какой именно компонент обёрнут в HOC:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|