PassFront
  1. PassFront
  2. База знаний
  3. Хуки

Какие данные помимо DOM можно хранить в useRef?

Хуки

useRef — универсальный контейнер: помимо DOM-узлов в нём хранят любые мутируемые значения, изменение которых не должно вызывать ререндер.

Типичные категории данных

Идентификаторы таймеров:

const timerRef = useRef(null);
timerRef.current = setTimeout(save, 2000);   // старт
clearTimeout(timerRef.current);              // отмена (дебаунс, автосейв)

Инстансы внешних объектов — живут дольше рендера, не сериализуются: WebSocket, AbortController, экземпляры библиотек (Chart, Map, редактор), IntersectionObserver.

Предыдущие значения props/state:

const prevStatus = useRef(status);
useEffect(() => { prevStatus.current = status; });
// сравнить «было/стало» в следующем рендере

Флаги жизненного цикла и защиты: isMounted, «запрос уже отправлен», «первый рендер» (пропустить эффект при монтировании), счётчик рендеров при отладке.

«Свежие» значения для стабильных колбэков — обход устаревших замыканий:

const handlerRef = useRef(onEvent);
useEffect(() => { handlerRef.current = onEvent; });
// подписка создаётся один раз, но зовёт всегда актуальный обработчик
useEffect(() => {
  const sub = source.subscribe((e) => handlerRef.current(e));
  return () => sub.unsubscribe();
}, []);

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

Критерий выбора ref против state

Отображается в UI → state (нужен ререндер). Служебное значение, нужное «между рендерами», → ref. Ошибка в обе стороны: отображаемое в ref «замораживает» UI, служебное в state — лишние ререндеры.

Коротко для собеседования

В useRef хранят всё мутируемое и не влияющее на рендер: id таймеров, инстансы (WebSocket, чарты, observers), предыдущие значения, флаги (isMounted, первый рендер), «свежие» колбэки для стабильных подписок, кеши. Правило: видно пользователю — state, служебное — ref.

Другие вопросы раздела