9. useRef и useReducer
React: Движок. Урок: useRef и useReducer
Заголовок раздела «React: Движок. Урок: useRef и useReducer»
В этом уроке мы рассмотрим два мощных хука React: useRef и useReducer. Они позволяют нам работать с DOM-элементами напрямую и управлять сложным состоянием компонентов.
useRef: Доступ к DOM и не только
Заголовок раздела «useRef: Доступ к DOM и не только»useRef возвращает мутабельный объект ref, который сохраняется на протяжении всего жизненного цикла компонента. Основное применение useRef - получение доступа к DOM-элементам. В отличие от состояния (useState), изменение значения ref не вызывает перерисовку компонента.
import React, { useRef, useEffect } from 'react';
function InputWithFocus() { // Создаем ref для input элемента const inputRef = useRef(null);
useEffect(() => { // После монтирования компонента фокусируемся на input inputRef.current.focus(); }, []); // Пустой массив зависимостей - useEffect сработает только один раз
return ( <input ref={inputRef} type="text" /> );}
export default InputWithFocus;В этом примере inputRef содержит ссылку на DOM-элемент <input>. Мы используем useEffect с пустым массивом зависимостей, чтобы сфокусироваться на input элементе только один раз, после монтирования компонента. inputRef.current содержит ссылку на сам input элемент.
useRef можно использовать и для хранения любых мутабельных значений, которые не должны вызывать перерисовку компонента при изменении. Например, можно хранить счетчик рендеров:
import React, { useRef, useEffect } from 'react';
function RenderCounter() { const renderCount = useRef(0);
useEffect(() => { renderCount.current = renderCount.current + 1; console.log('Компонент перерендерился ', renderCount.current, ' раз'); });
return ( <div> Этот компонент перерендерился: {renderCount.current} раз. (Не отображается!) </div> );}
export default RenderCounter;Обратите внимание, что изменение renderCount.current не вызывает перерисовку компонента. Значение обновляется, но компонент не перерисовывается, поэтому текст на экране не меняется.
useReducer: Управление сложным состоянием
Заголовок раздела «useReducer: Управление сложным состоянием»useReducer - это альтернатива useState, которая особенно полезна для управления сложным состоянием, включающим множество подзначений или когда следующее состояние зависит от предыдущего. useReducer принимает редьюсер (функцию, которая определяет, как состояние должно изменяться в ответ на действия) и начальное состояние. Он возвращает текущее состояние и функцию dispatch, которая используется для отправки действий редьюсеру.
import React, { useReducer } from 'react';
// Редьюсер - функция, которая принимает текущее состояние и action, и возвращает новое состояниеfunction reducer(state, action) { switch (action.type) { case 'increment': return { count: state.count + 1 }; case 'decrement': return { count: state.count - 1 }; default: throw new Error(); }}
function Counter() { // useReducer возвращает текущее состояние (state) и функцию dispatch const [state, dispatch] = useReducer(reducer, { count: 0 });
return ( <div> Счетчик: {state.count} <button onClick={() => dispatch({ type: 'increment' })}>Increment</button> <button onClick={() => dispatch({ type: 'decrement' })}>Decrement</button> </div> );}
export default Counter;В этом примере reducer определяет, как состояние count должно изменяться при отправке действий increment и decrement. dispatch используется для отправки этих действий редьюсеру.
Жизненный пример
Заголовок раздела «Жизненный пример»useRef часто используется для реализации кастомных хуков, например, хука для измерения размера DOM-элемента, или для управления фокусом в формах.
useReducer широко применяется в Redux и других библиотеках управления состоянием. Он также полезен для управления сложным состоянием внутри отдельных компонентов, например, при работе с формами, имеющими множество полей и сложную логику валидации. Многие библиотеки компонентов используют useReducer для управления внутренним состоянием сложных виджетов.
Ключевые моменты
Заголовок раздела «Ключевые моменты»useRefпозволяет получить доступ к DOM-элементам и хранить мутабельные значения, не вызывая перерисовку.useReducerпредназначен для управления сложным состоянием, особенно когда следующее состояние зависит от предыдущего.useReducerиспользует редьюсер - функцию, определяющую, как состояние изменяется в ответ на действия.useRefне вызывает перерисовку при изменении.current, в отличие отuseState.useReducerпредоставляет более структурированный способ управления состоянием, чемuseState, особенно для сложных сценариев.