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

Объясни, будет ли вызван useEffect, если у него в зависимостях изменился Ref: от чего это зависит и почему.

Хуки

Зависит от того, что именно стоит в массиве зависимостей: сам ref-объект или ref.current. В обоих случаях поведение неинтуитивное — и это классическая ловушка.

Случай 1: в зависимостях сам ref

const ref = useRef(0);
useEffect(() => { ... }, [ref]); // бессмысленно

Эффект вызовется только при монтировании: ref-объект стабилен — это одна и та же ссылка все рендеры. Изменение ref.current его не меняет, сравнение Object.is всегда «равно».

Случай 2: в зависимостях ref.current

useEffect(() => { ... }, [ref.current]); // ненадёжно

Здесь тонкость: запись в ref.current не вызывает ререндер, а зависимости сравниваются только во время рендера. Если current изменился «между рендерами», React об этом не узнает — эффект не запустится. Если же позже случится ререндер по другой причине (state, родитель), сравнение увидит новое значение current — и эффект внезапно выполнится. Итог: эффект срабатывает не «при изменении ref», а «при первом ререндере после изменения» — недетерминированно.

Почему так задумано

Ref — намеренно нереактивное хранилище: React не отслеживает его изменения. «Реагировать на изменение ref» — противоречие; линтер exhaustive-deps сам ref в deps не требует.

Что делать вместо

  • Нужна реакция на изменение значения → хранить его в state.
  • Нужна реакция на появление DOM-узла → callback ref (+ state при необходимости).
  • Ref в эффекте использовать можно — просто не как триггер, а как чтение текущего значения.

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

Сам ref в deps стабилен — эффект не перезапустится никогда; ref.current в deps срабатывает только при «случайном» ререндере после изменения — недетерминированно, поскольку запись в ref рендер не вызывает, а deps сравниваются лишь при рендере. Для реактивности — state или callback ref; ref — принципиально нереактивен.

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