В чем разница useRef и useState в React
Что проверяют
Понимаете ли вы, что рендер запускает не любое изменение данных, а только изменение состояния. Заодно смотрят, знаете ли вы правила работы с ссылками.
Как отвечать
useState хранит состояние: его изменение через сеттер планирует повторный рендер, и новое значение попадает в разметку. useRef хранит изменяемый контейнер { current }, который переживает рендеры, но его изменение рендер не вызывает.
Когда что брать:
- useState: всё, что видно на экране. Текст поля, открыт ли список, загруженные данные, счётчик;
- useRef: ссылка на DOM-узел (
<input ref={inputRef} />), идентификатор таймера, предыдущее значение, флаг «первый рендер», накопитель, который читают только в обработчиках.
Правила, которые и хотят услышать:
- ссылку нельзя читать и писать во время рендера, только в обработчиках и эффектах. Рендер должен быть чистым, а ссылка это побочное состояние;
- значение ссылки не участвует в сравнении зависимостей: положив в неё объект, вы не заставите эффект перезапуститься;
- ссылка не заменяет состояние, если значение влияет на разметку. Изменение
ref.currentэкран не обновит, и появится расхождение между данными и картинкой.
const timer = useRef(null);
useEffect(() => () => clearInterval(timer.current), []); // храним id таймераПолезно добавить: useRef часто используют как замену устаревшему полю экземпляра класса, а для сохранения свежего колбэка есть распространённый приём с ссылкой, которую обновляют в эффекте.
Где спотыкаются
Кладут в ссылку данные для отображения и не понимают, почему экран не обновился.
Читают ref.current прямо в теле компонента и получают несогласованный результат при конкурентном рендере.
Забывают, что ref из useRef не то же самое, что колбэк-ссылка: для реакции на появление узла в DOM нужен именно колбэк или эффект.