React useRef, forwardRef и некоторые проблемы, с которыми вы можете столкнуться при работе с ними

React useRef, forwardRef и некоторые проблемы, с которыми вы можете столкнуться при работе с ними

23 мая 2022 г.

Привет ребята. В этой статье я хочу поделиться с вами хуками useRef и forwardRef в React, но эта статья не о том, что такое хуки реакции, когда они были созданы и почему мы должны их использовать.


Итак, если вы не знакомы с реактивными хуками или с реакцией, вам следует прочитать о том, что такое реакция, что такое хуки, и поиграть с простыми хуками, такими как useState, useEffect, а после вы можете вернуться сюда.


Назначение useRef состоит в том, чтобы сохранять переменные между перерисовкой компонентов реакции. Как вы знаете, при каждом рендере все переменные и функции будут пересоздаваться. И, например, если вы хотите сохранить какое-то значение во время ререндеринга, изменять его только тогда, когда вам это нужно, вы можете использовать для этой цели useRef.


И вы можете спросить, зачем нам useRef, если у нас есть useState, который может сохранять значение между ререндерами и мы можем изменить это значение в любой момент. Ответ: да, можете. Но если вы измените свое состояние, компонент, который использует это состояние, будет перерендерен. Вместо useState изменение значения useRef не приводит к повторному рендерингу.


Давайте проверим, как работает useRef, а затем сравним useRef и useState.



Как видите, создание ref почти такое же, как useState, но оно возвращает только одно значение без сеттера. Проверим, какое значение будет внутри нашего ref:



useRef вернет объект со свойством current, которое содержит начальное значение, которое вы можете передать во время инициализации useRef.


Допустим, мы хотим изменить имя нашего значения. Вы можете сделать это очень просто:



Изменение имени внутри ref не приведет к повторному рендерингу страницы.


Давайте сравним useRef с useState. Я добавлю useEffect, setInterval, где use ref меняется каждые 300 миллисекунд:


используйте ссылку, изменяющуюся каждые 300 миллисекунд, не вызывает повторную визуализацию страницы


Только один рендеринг


Как мы видим, наш рендеринг не вызывается каждые 300 миллисекунд.


Но давайте сделаем то же самое с useState:


установить состояние внутри интервала запускает рендеринг страницы каждый интервал времени


Наш setUserState вызывает повторную визуализацию каждые 300 миллисекунд.


Перерисовка страницы в каждый интервал времени


Зная это, если вы хотите сохранить какое-то значение, измените его, но вам не нужны повторные рендеры, вы можете использовать хук useRef. Это похоже на this в компоненте класса, когда вы меняете какое-то свойство, используя ключевое слово this вместо вызова this.setState() в компоненте класса.


А теперь давайте проверим пример с наиболее частым использованием useRef на практике:


Представьте, что у вас есть какой-то редактор (текстовое поле) на странице, и вы хотите сделать фокус, как только пользователь увидит это текстовое поле на странице. Как вы можете это сделать?


В чистом Javascript вы можете сделать что-то вроде:


const textarea = document.querySelector('#editor');


текстовая область.фокус();


Но как он реагирует? Для этого вы должны использовать useRef и прикрепить его к элементу DOM. Давайте проверим пример:


Пример использования useRef для элемента DOM


Как видите, это действительно просто. Вы создаете userRef и передаете его элементу DOM, используя атрибут ref: <textarea ref={textareaRef} />


Вы можете установить ссылку на элементы, а затем работать как с простым DOM API. например, добавить фокус, addEventListener, removeEventListener.


Чтобы получить доступ к этой ссылке, используйте другой хук, useEffect, как вы можете видеть на картинке. В этом случае вы можете быть уверены, что элемент DOM был создан.


Использование useRef является более важным способом работы с DOM, и в целом, если вы можете, используйте реагирующий API вместо собственного API DOM. Но иногда у нас нет возможности сделать что-то, используя только реагирующий API. В таких случаях можно использовать ref и нативный DOM API.


Например, если вы используете внешнюю библиотеку, которая не работает с react, но вам нужно как-то подключить эту библиотеку к DOM-элементу (google maps или chart.js), хорошим решением будет useRef и нативный DOM API. К счастью, многие современные библиотеки имеют реагирующие оболочки, так что вы можете их использовать.


Другой пример, если вам нужны координаты какого-то элемента, вы можете установить useRef для этого элемента и вызвать метод getBoundingClientRect.


==Важный момент==: в качестве рефов можно использовать только нативные DOM-элементы, если поставить реф на свой компонент, то он работать не будет.


Так не пойдет:


Вы не можете использовать ref для своих пользовательских компонентов


В этом примере textareaRef.current содержит значение по умолчанию, равное null.


Но что, если вы хотите передать эту ссылку в качестве реквизита дочернему компоненту? Как в примере ниже:


ссылка как дополнение к дочернему компоненту


К сожалению, это тоже не работает.


Но есть решение. Если вы хотите создать повторно используемый компонент и передать ссылку от родителя к дочерним элементам, вы можете использовать forwardRef.


forwardRef — это HOC, который принимает компоненты в качестве параметра. И внутри этого компонента у нас есть доступ к свойствам (первый параметр) и к ссылке (второй параметр). Давайте взглянем:


Пример использования forwardRef.


Как видите, forwardRef — это просто функция, импортированная из реакции. Эта функция принимает компонент в качестве параметра. Этот компонент имеет первый параметр — props, а второй — ref из родительского компонента.


И, как видите, мы также должны установить отображаемое имя, потому что forwardRef очищает его. Как использовать этот компонент от родителя?


Использование Forwardref


Вы можете использовать этот компонент, который обернут с помощью forwarRef, как простой компонент, но здесь мы передаем ref как свойство. Например, как видите, мы создали 2 textarea и 2 useRef. Внутри useEffect вы можете указать некоторые условия и решить, что вы хотите делать с любой из этих ссылок.


В общем, это все, что вам следует знать перед началом работы с useRef и forwardRef.


Попробуйте поиграть с ними обоими. На практике это не очень распространенная вещь, которую вы будете использовать, но иногда, когда реакции API недостаточно, они действительно полезны.


Подытожим все, что мы знаем о useRef и forwardRef:


  • useRef часто используется как ссылка на какой-то элемент DOM, когда недостаточно API реакции.

  • Работайте с ref внутри useEffect, чтобы убедиться, что элемент DOM был создан на странице.

  • useRef также можно использовать, если вы хотите иметь переменную, которая будет хранить некоторую информацию между рендерингом, и вы не хотите вызывать рендеринг страницы после изменения этой переменной (в отличие от useState).

  • useRef можно было использовать только для нативных элементов DOM (теги HTML).

  • если вы хотите передать ref в качестве реквизита дочернему компоненту, вы должны обернуть свой дочерний компонент в forwardRef HOC. И не забудьте изменить displayName вашего компонента после использования forwardRef.


Оригинал
PREVIOUS ARTICLE
NEXT ARTICLE