Хук useEffect и зависимости

Учимся выполнять побочные эффекты — то, что выходит за рамки отрисовки: таймеры, подписки, обращения к внешнему миру.

useEffect — хук, который запускает код после отрисовки компонента; используется для побочных эффектов, не относящихся напрямую к рендеру.

Что такое побочный эффект

Компонент в идеале просто превращает данные в JSX. Но иногда нужно «достучаться до внешнего мира»: запустить таймер, поменять заголовок вкладки, подписаться на событие, загрузить данные. Это и есть побочные эффекты — действия за пределами вычисления разметки. Делать их прямо в теле компонента нельзя (тело должно быть чистым), для них есть useEffect.

import { useEffect, useState } from "react";

function Title() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    document.title = `Кликов: ${count}`;
  });

  return <button onClick={() => setCount(count + 1)}>Клик</button>;
}

После каждой отрисовки React выполнит функцию-эффект и обновит заголовок вкладки.

Массив зависимостей

Второй аргумент useEffect — массив зависимостей. Он управляет тем, когда эффект перезапускается. Три варианта:

ЗаписьКогда запускается эффект
useEffect(fn)после каждой отрисовки
useEffect(fn, [])один раз, при монтировании компонента
useEffect(fn, [a, b])при монтировании и когда меняется a или b

Пустой массив: «только при монтировании»

Пустой массив [] означает «у эффекта нет зависимостей, запусти его один раз». Это типичный способ сделать что-то при появлении компонента — например, поставить фокус или запросить данные:

useEffect(() => {
  console.log("Компонент появился на экране");
}, []); // [] → только один раз

Зависимости: «когда меняется значение»

Перечислив в массиве значения, вы говорите: «перезапусти эффект, если хоть одно изменилось». Здесь заголовок обновляется только при смене count:

useEffect(() => {
  document.title = `Кликов: ${count}`;
}, [count]); // перезапуск только при изменении count

Правило: указывайте всё, что используете

В массив зависимостей нужно класть все значения из компонента (пропсы, состояние), которые эффект использует внутри. Если что-то забыть, эффект будет работать со «старыми» данными — частый источник багов. Линтер ESLint обычно подсказывает недостающие зависимости.

Как читать массив зависимостей

Думайте о нём как о вопросе «при изменении чего нужно снова выполнить этот эффект?». Ответ «ничего» → []. Ответ «при смене пользователя» → [userId]. Ответ «всегда» → массив не указывают (но это нужно редко).

Итог

  • useEffect выполняет побочные эффекты после отрисовки (таймеры, подписки, работа с внешним миром).
  • Массив зависимостей управляет частотой: [] — один раз, [a] — при смене a, без массива — всегда.
  • Указывайте в зависимостях все используемые значения, иначе эффект увидит устаревшие данные.
Проверьте себя
1. Что такое побочный эффект, ради которого нужен useEffect?
AЛюбой вызов console.log
BДействие за пределами отрисовки: таймер, подписка, запрос данных, изменение title
CОшибка в компоненте
DПерерисовка компонента
2. Что означает пустой массив зависимостей useEffect(fn, [])?
AЭффект не запустится никогда
BЭффект запустится один раз при монтировании компонента
CЭффект запустится после каждой отрисовки
DЭто синтаксическая ошибка
3. Что произойдёт с useEffect(fn, [count]) при изменении count?
AНичего, массив игнорируется
BЭффект перезапустится
CКомпонент удалится
DЭффект выполнится только при первом рендере
Поддержать проект