Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

useRef

Иногда нужен прямой доступ к элементу страницы: поставить курсор в поле, прокрутить список, измерить размер. Для этого есть хук useRef. Он создаёт ссылку (ref) — объект с единственным свойством current, которое сохраняется между отрисовками. Изменение current не вызывает перерисовку, в этом главное отличие от состояния.

Ссылка на DOM-элемент

Поставим курсор в поле формы добавления задачи по кнопке. В src/components/AddTodoForm.jsx:

// src/components/AddTodoForm.jsx
import { useRef } from 'react';
 
export default function AddTodoForm() {
  const inputRef = useRef(null);
 
  function handleFocus() {
    inputRef.current.focus();
  }
 
  return (
    <>
      <input ref={inputRef} placeholder="Новая задача" />
      <button onClick={handleFocus}>Ввести задачу</button>
    </>
  );
}

Атрибут ref говорит React: «положи в inputRef.current этот DOM-элемент». После нажатия на кнопку курсор окажется в поле.

Фокус после отправки

Удобно возвращать курсор в поле после добавления задачи, чтобы сразу вводить следующую:

// src/components/AddTodoForm.jsx
function handleSubmit(event) {
  event.preventDefault();
  onAdd(text);
  setText('');
  inputRef.current.focus();
}

Добавьте задачу — поле очистится, а курсор останется в нём.

Значение без перерисовки

Ref подходит и для данных, которые не выводятся на страницу, например номера таймера. Секундомер — src/components/Stopwatch.jsx:

// src/components/Stopwatch.jsx
import { useRef, useState } from 'react';
 
export default function Stopwatch() {
  const [seconds, setSeconds] = useState(0);
  const timerRef = useRef(null);
 
  function start() {
    timerRef.current = setInterval(() => setSeconds((value) => value + 1), 1000);
  }
 
  function stop() {
    clearInterval(timerRef.current);
  }
 
  return (
    <>
      <p>Прошло: {seconds} с</p>
      <button onClick={start}>Старт</button>
      <button onClick={stop}>Стоп</button>
    </>
  );
}

Номер таймера нужен только кнопке «Стоп», показывать его не нужно, поэтому он хранится в ref, а не в состоянии.

Ref в своём компоненте

В React 19 ref можно передать своему компоненту как обычный проп и прикрепить к элементу внутри:

// src/components/TextInput.jsx
export default function TextInput({ ref, ...props }) {
  return <input ref={ref} className="text-input" {...props} />;
}

Теперь <TextInput ref={inputRef} /> работает так же, как input. В старых версиях для этого требовалась функция forwardRef.

useRef или useState

useRefuseState
Изменение перерисовывает компонентНетДа
Как менятьref.current = значениеЧерез сеттер
Для чегоDOM-элементы, таймеры, служебные значенияВсё, что видно на экране

Частая ошибка

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

// Неправильно: при первой отрисовке inputRef.current равен null.
const inputRef = useRef(null);
inputRef.current.focus();

Чтобы поставить фокус сразу после появления, вызовите focus() внутри useEffect или используйте атрибут autoFocus.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.