Spec-Zone.ru › React 18

useRef

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

const ref = useRef(initialValue)
  • Ссылка
    • useRef(initialValue)
  • Использование
    • Ссылка на значение с помощью ref
    • Работа с DOM с помощью ref
    • Избегание повторного создания содержимого ref
  • Отладка
    • Не удаётся получить ссылку на пользовательский компонент

Ссылка

useRef(initialValue)

Вызовите useRef на верхнем уровне вашего компонента, чтобы объявить ссылку.

import { useRef } from 'react';

function MyComponent() {
  const intervalRef = useRef(0);
  const inputRef = useRef(null);
  // ...

См. дополнительные примеры ниже.

Параметры

  • initialValue: Значение, которое вы хотите, чтобы свойство current объекта ref имело изначально. Это может быть значение любого типа. Этот аргумент игнорируется после начального рендеринга.

Возвращаемое значение

useRef возвращает объект с единственным свойством:

  • current: Изначально оно устанавливается в переданное вами initialValue. Позже вы можете установить его на другое значение. Если вы передадите объект ref в React в качестве атрибута ref узлу JSX, React установит его свойство current.

При последующих рендерингах useRef будет возвращать тот же объект.

Ограничения

  • Вы можете изменить свойство ref.current. В отличие от состояния, оно изменяемое. Однако, если оно содержит объект, используемый для отрисовки (например, часть вашего состояния), то вам не следует изменять этот объект.
  • При изменении свойства ref.current React не перерисовывает ваш компонент. React не знает, когда вы его меняете, потому что ref — это обычный объект JavaScript.
  • Не записывайте и не читайте ref.current во время рендеринга, за исключением инициализации. Это делает поведение вашего компонента непредсказуемым.
  • В режиме Strict Mode React будет вызывать вашу функцию компонента дважды для того, чтобы помочь вам найти случайные ошибки. Это поведение только для разработки и не влияет на производство. Каждый объект ref будет создан дважды, но одна из версий будет отброшена. Если функция вашего компонента чистая (как и должно быть), это не должно повлиять на поведение.

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

Ссылка на значение с помощью ref

Вызовите useRef на верхнем уровне вашего компонента, чтобы объявить одну или несколько ссылок.

import { useRef } from 'react';

function Stopwatch() {
  const intervalRef = useRef(0);
  // ...

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

При последующих рендерингах useRef будет возвращать тот же объект. Вы можете изменить его свойство current для хранения информации и чтения ее позже. Это может напомнить вам о состоянии, но есть важное различие.

Изменение ref не вызывает перерендеринг. Это означает, что ссылки идеально подходят для хранения информации, которая не влияет на визуальный вывод вашего компонента. Например, если вам нужно хранить идентификатор интервала и извлечь его позже, вы можете поместить его в ref. Чтобы обновить значение внутри ref, вам нужно вручную изменить его current свойство:

function handleStartClick() {
  const intervalId = setInterval(() => {
    // ...
  }, 1000);
  intervalRef.current = intervalId;
}

Позже вы можете прочитать этот идентификатор интервала из ref, чтобы вы могли вызвать остановить этот интервал:

function handleStopClick() {
  const intervalId = intervalRef.current;
  clearInterval(intervalId);
}

Используя ref, вы обеспечиваете:

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

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

Подводные камни

Не записывайте и не читайте ref.current во время рендеринга.

React ожидает, что тело вашего компонента ведет себя как чистая функция:

  • Если входные данные (свойства, состояние и контекст) одинаковы, он должен возвращать точно такой же JSX.
  • Вызов его в разном порядке или с разными аргументами не должен влиять на результаты других вызовов.

Чтение или запись ref во время рендеринга нарушает эти ожидания.

function MyComponent() {
  // ...
  // 🚩 Don't write a ref during rendering
  myRef.current = 123;
  // ...
  // 🚩 Don't read a ref during rendering
  return <h1>{myOtherRef.current}</h1>;
}

Вы можете читать или записывать ref из обработчиков событий или эффектов вместо этого.

function MyComponent() {
  // ...
  useEffect(() => {
    // ✅ You can read or write refs in effects
    myRef.current = 123;
  });
  // ...
  function handleClick() {
    // ✅ You can read or write refs in event handlers
    doSomething(myOtherRef.current);
  }
  // ...
}

Если вам необходимо читать или записывать что-то во время рендеринга, используйте состояние вместо этого.

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


Работа с DOM с помощью ref

Часто ссылки используются для работы с DOM. React поддерживает это встроенно.

Сначала объявите объект ref с начальным значением null:

import { useRef } from 'react';

function MyComponent() {
  const inputRef = useRef(null);
  // ...

Затем передайте ваш объект ref в качестве атрибута ref JSX узла DOM, который вы хотите изменить:

  // ...
  return <input ref={inputRef} />;

После того, как React создает узел DOM и выведет его на экран, React установит current свойство вашего объекта ref на этот узел DOM. Теперь вы можете получить доступ к узлу DOM <input> и вызвать методы, такие как focus():

  function handleClick() {
    inputRef.current.focus();
  }

React установит current свойство обратно к null при удалении узла с экрана.

Узнайте больше о работе с DOM с помощью ref.


Избегание повторного создания содержимого ref

React сохраняет исходное значение ref один раз и игнорирует его при последующих рендерингах.

function Video() {
  const playerRef = useRef(new VideoPlayer());
  // ...

Хотя результат new VideoPlayer() используется только для начального рендеринга, вы всё равно вызываете эту функцию при каждом рендеринге. Это может быть накладным, если она создаёт дорогостоящие объекты.

Для решения этой проблемы вы можете инициализировать ref так:

function Video() {
  const playerRef = useRef(null);
  if (playerRef.current === null) {
    playerRef.current = new VideoPlayer();
  }
  // ...

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

Подробное описание

Как избежать проверок на null при последующей инициализации useRef

Если вы используете проверяющий тип и не хотите всегда проверять null, вы можете попробовать такой шаблон вместо этого:

function Video() {
  const playerRef = useRef(null);

  function getPlayer() {
    if (playerRef.current !== null) {
      return playerRef.current;
    }
    const player = new VideoPlayer();
    playerRef.current = player;
    return player;
  }

  // ...

Здесь сам playerRef является допустимым значением null. Однако вы должны убедить свой проверяющий тип в том, что нет случаев, когда getPlayer() возвращает null. Затем используйте getPlayer() в своих обработчиках событий.


Отладка

Не удаётся получить ссылку на пользовательский компонент

Если вы пытаетесь передать ref в свой собственный компонент так:

const inputRef = useRef(null);

return <MyInput ref={inputRef} />;

В консоли может появиться ошибка:

Консоль
Предупреждение: Функциональным компонентам нельзя задавать ссылки. Попытки доступа к этой ссылке завершатся ошибкой. Вы имели в виду React.forwardRef()?

По умолчанию ваши собственные компоненты не предоставляют ссылки на узлы DOM внутри них.

Чтобы исправить это, найдите компонент, к которому вы хотите получить ссылку:

export default function MyInput({ value, onChange }) {
  return (
    <input
      value={value}
      onChange={onChange}
    />
  );
}

И затем оберните его в forwardRef, как это:

import { forwardRef } from 'react';

const MyInput = forwardRef(({ value, onChange }, ref) => {
  return (
    <input
      value={value}
      onChange={onChange}
      ref={ref}
    />
  );
});

export default MyInput;

Тогда родительский компонент сможет получить ссылку на него.

Узнайте больше о доступе к узлам DOM другого компонента.

© 2013–present Facebook Inc.
Licensed under the Creative Commons Attribution 4.0 International Public License.
https://react.dev/reference/react/useRef

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API