React useRef

Хук useRef позволяет сохранять значения между рендерами.

Он может использоваться для хранения изменяемых значений, которые не вызывают повторного рендеринга при обновлении.

Может использоваться для прямого доступа к элементам DOM.


Не вызывает повторного рендеринга

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

Чтобы избежать этого, можно использовать хук useRef.

Пример

Используем useRef, чтобы отслеживать количество рендеров приложения:


import { useState, useRef, useEffect } from 'react';
import { createRoot } from 'react-dom/client';

function App() {
  const [inputValue, setInputValue] = useState("");
  const count = useRef(0);

  useEffect(() => {
    count.current = count.current + 1;
  });

  return (
    <>
      <p>Введите текст в поле:</p>
      <input
        type="text"
        value={inputValue}
        onChange={(e) => setInputValue(e.target.value)}
      />
      <h1>Количество рендеров: {count.current}</h1>
    </>
  );
}

createRoot(document.getElementById('root')).render(
  <App />
);

useRef() возвращает только один элемент — объект current.

При инициализации useRef мы устанавливаем начальное значение: useRef(0).

Это похоже на объявление константы: const count = {current: 0};. Доступ к значению осуществляется через count.current.

Доступ к элементам DOM

Хук useRef часто используется для прямого доступа к элементам DOM.

Сначала создаем реф с помощью хука useRef: const inputElement = useRef();.

Затем присоединяем реф к элементу DOM с помощью атрибута ref в JSX: <input type="text" ref={inputElement} />.

Наконец, получаем доступ к элементу DOM через свойство current: inputElement.current.

Пример

Используем useRef, чтобы поставить фокус на поле ввода:


import { useRef } from 'react';
import { createRoot } from 'react-dom/client';

function App() {
  const inputElement = useRef();

  const focusInput = () => {
    inputElement.current.focus();
  };

  return (
    <>
      <input type="text" ref={inputElement} />
      <button onClick={focusInput}>Поставить фокус</button>
    </>
  );
}

createRoot(document.getElementById('root')).render(
  <App />
);

В данном примере поле ввода получает фокус при клике на кнопку, так как функция onClick вызывает inputElement.current.focus().


Отслеживание изменений состояния

Хук useRef также можно использовать для сохранения прежних значений состояния.

Это возможно благодаря тому, что значения useRef сохраняются между рендерами.

Пример

Используем useRef, чтобы следить за предыдущими значениями состояния:


import { useRef, useState, useEffect } from 'react';
import { createRoot } from 'react-dom/client';

function App() {
  const [inputValue, setInputValue] = useState("");
  const previousInputValue = useRef("");

  useEffect(() => {
    previousInputValue.current = inputValue;
  }, [inputValue]);

  return (
    <>
      <input
        type="text"
        value={inputValue}
        onChange={(e) => setInputValue(e.target.value)}
      />
      <h2>Текущее значение: {inputValue}</h2>
      <h2>Предыдущее значение: {previousInputValue.current}</h2>
    </>
  );
}

createRoot(document.getElementById('root')).render(
  <App />
);

В этом примере мы объединили useState, useEffect и useRef, чтобы отслеживать предыдущее состояние.

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