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

Какие нюансы useEffect важны на практике и как их применять?

Хуки

Практические нюансы useEffect — то, на чём спотыкаются чаще всего, и то, что отличает уверенное владение хуком.

Время выполнения

Эффект срабатывает после коммита и отрисовки кадра — не блокирует показ. Нужно измерить/поправить DOM до кадра (позиционирование, скролл) — useLayoutEffect.

Зависимости

  • Сравнение поверхностное (Object.is): объекты/функции из рендера — «всегда новые», эффект перезапускается каждый рендер. Лечение: примитивы в deps, useMemo/useCallback, перенос значения внутрь эффекта.
  • Пропущенная зависимость → устаревшее замыкание: таймер/подписка видят state первого рендера. Лечение: функциональные сеттеры setX((x) => ...), честные deps, ref для «свежего» значения.
  • Сеттеры useState, dispatch и ref-объект стабильны — в deps не нужны.

Cleanup

Вызывается перед каждым перезапуском и при размонтировании. Обязателен для подписок, таймеров, соединений, отмены запросов (AbortController/флаг), иначе утечки и гонки.

Асинхронность

useEffect(async () => ...) нельзя: колбэк обязан вернуть функцию или undefined. Асинхронность — внутри, с защитой от гонок.

StrictMode

В dev эффекты монтирования выполняются дважды (mount → cleanup → mount). Двойной запрос — не баг, а проверка идемпотентности и cleanup.

Когда эффект не нужен

Производные данные — вычислять в рендере/useMemo, не «effect + setState». Реакция на клик — в обработчике. Серверные данные — React Query. Цепочки эффектов, триггерящих друг друга, — признак неправильной модели.

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

Главное: эффект после отрисовки (для «до кадра» — useLayoutEffect); deps сравниваются по Object.is (нестабильные ссылки и stale closures — главные баги); cleanup обязателен и вызывается перед каждым перезапуском; async напрямую нельзя; StrictMode дублирует монтирование в dev; для вычислений, событий и серверных данных эффект не нужен.

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