Как убрать лишние зависимости в useEffect для избежания лишних рендеров
Что проверяют
Понимаете ли вы, что эффект не вызывает рендер, а запускается после него, и что зависимости нельзя просто вычеркнуть из массива. Вопрос в том, как переписать код, чтобы лишнего не было. Следом часто просят найти причину бесконечного цикла или объяснить устаревшее замыкание.
Как отвечать
Сначала правило: в массив попадает всё реактивное, что читается внутри эффекта, то есть пропсы, состояние и производные от них. Это проверяет eslint-plugin-react-hooks (exhaustive-deps). Лишние запуски убирают правкой кода, а не списка:
- объект или функция из рендера:
{...}и() => {}каждый раз новые, иObject.isсчитает их изменившимися. Перенесите их внутрь эффекта или за пределы компонента, а если нужны снаружи, стабилизируйте черезuseMemoиuseCallback; - примитивы вместо объектов: вместо
[options]возьмите[options.userId]; - функциональное обновление:
setCount(c => c + 1)вместоsetCount(count + 1)убираетcountиз зависимостей; - нереактивная логика: значение, которое нужно прочитать, но не нужно на него перезапускаться, выносят в
useEffectEvent, в React 19.2 он стабилен. В старых версиях для этого держат значение вuseRef; - эффект не нужен: производные данные считают прямо в рендере, реакцию на клик пишут в обработчике, сброс состояния при смене пропса делают через
key.
Для загрузки данных добавьте отмену: AbortController или флаг ignore в функции очистки, иначе медленный старый ответ перезапишет новый. Загрузку в проекте удобнее отдать TanStack Query или SWR.
React Compiler сам мемоизирует значения и снимает часть проблемы, но правило полного массива остаётся.
Где спотыкаются
Удаляют зависимость и глушат линтер комментарием. Эффект читает устаревшие значения из прошлого рендера, и баг проявляется только при определённом порядке действий.
Оборачивают всё подряд в useCallback, а объект из пропсов родителя всё равно новый на каждом рендере. Мемоизация работает там, где значение создаётся.
Принимают двойной запуск эффекта в StrictMode за лишний рендер и «чинят» его зависимостями. Это проверка функции очистки в режиме разработки, в продакшене второго запуска нет.