← Назад к вопросам

А если совсем не передавать массив зависимостей

2.3 Middle🔥 151 комментариев
#JavaScript Core

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Что происходит если не передавать массив зависимостей в useEffect

Это критичный вопрос, который часто задают на интервью. Поведение отличается от случаев, когда передаёшь пустой массив [] или конкретные зависимости.

Три варианта

1. useEffect БЕЗ массива зависимостей

useEffect(() => {
  console.log('Эффект выполнен');
  // НЕТ второго параметра
});

Поведение:

  • Эффект выполняется ПОСЛЕ КАЖДОГО рендера компонента
  • Выполняется каждый раз, когда компонент перерисовывается
  • Идеальна для эффектов, которые должны синхронизироваться с каждым обновлением

2. useEffect с пустым массивом []

useEffect(() => {
  console.log('Эффект выполнен');
}, []);

Поведение:

  • Эффект выполняется ОДИН РАЗ при монтировании компонента
  • НЕ выполняется при обновлениях
  • Используется для инициализации и загрузки данных

3. useEffect с конкретными зависимостями

useEffect(() => {
  console.log('Эффект выполнен');
}, [dependency]);

Поведение:

  • Эффект выполняется при ИЗМЕНЕНИИ зависимостей
  • Выполняется один раз при монтировании
  • Затем выполняется когда dependency изменяется

Практический пример

function Counter() {
  const [count, setCount] = useState(0);
  const [name, setName] = useState('');
  
  // БЕЗ массива зависимостей
  useEffect(() => {
    console.log('Без зависимостей: выполняется после КАЖДОГО рендера');
  });
  
  // С пустым массивом
  useEffect(() => {
    console.log('С []: выполняется ОДИН РАЗ при монтировании');
  }, []);
  
  // С зависимостями
  useEffect(() => {
    console.log('С [count]: выполняется при изменении count');
  }, [count]);
  
  return (
    <div>
      <p>Счётчик: {count}</p>
      <p>Имя: {name}</p>
      <button onClick={() => setCount(count + 1)}>Увеличить счётчик</button>
      <button onClick={() => setName('Иван')}>Установить имя</button>
    </div>
  );
}

Порядок выполнения

Когда ты нажимаешь кнопку "Увеличить счётчик":

1. State обновляется (count = 1)
2. Компонент перерисовывается
3. Эффект БЕЗ зависимостей выполняется
4. Эффект с [count] выполняется
5. Эффект с [] НЕ выполняется

Когда ты нажимаешь кнопку "Установить имя":

1. State обновляется (name = 'Иван')
2. Компонент перерисовывается
3. Эффект БЕЗ зависимостей выполняется
4. Эффект с [count] НЕ выполняется
5. Эффект с [] НЕ выполняется

Когда это может быть проблемой

Бесконечный цикл

function BadComponent() {
  const [data, setData] = useState(null);
  
  useEffect(() => {
    // БЕЗ массива зависимостей - ПЛОХО!
    fetch('/api/data')
      .then(res => res.json())
      .then(result => setData(result)); // Обновляет state
    // Это вызывает новый рендер
    // Который снова запускает эффект
    // Бесконечный цикл!
  });
  
  return <div>{data?.name}</div>;
}

Результат: бесконечные запросы к серверу, падение приложения.

Правильный вариант

function GoodComponent() {
  const [data, setData] = useState(null);
  
  useEffect(() => {
    // С пустым массивом - ПРАВИЛЬНО
    fetch('/api/data')
      .then(res => res.json())
      .then(result => setData(result));
  }, []); // Выполнится только один раз
  
  return <div>{data?.name}</div>;
}

Когда нужно БЕЗ массива зависимостей

Используй useEffect без массива зависимостей редко, но есть легальные случаи:

Пример 1: Синхронизация title

function Page({ title }) {
  useEffect(() => {
    document.title = title; // Обновляется после каждого рендера
    // Это нормально и необходимо
  });
  
  return <div>Содержание</div>;
}

Пример 2: Отслеживание размера окна

function ResponsiveComponent() {
  const [windowSize, setWindowSize] = useState(window.innerWidth);
  
  useEffect(() => {
    const handleResize = () => {
      setWindowSize(window.innerWidth);
    };
    
    window.addEventListener('resize', handleResize);
    
    return () => {
      window.removeEventListener('resize', handleResize);
    };
  }); // БЕЗ зависимостей - нормально для этого случая
  
  return <div>Ширина: {windowSize}</div>;
}

Сравнительная таблица

ВариантКоличество выполненийКогдаСлучаи использования
Без массиваПосле КАЖДОГО рендераВсегдаРедко, синхронизация
[]1 (при монтировании)Один разЗагрузка данных, инициализация
[dep1, dep2]Когда изменяются зависимостиПри измененииРеактивные обновления

ESLint правило

React ESLint plugin предупреждает об отсутствии массива зависимостей:

// ESLint предупредит
useEffect(() => {
  console.log(count); // count используется, но не в зависимостях
}, []); // ОШИБКА: count должен быть в зависимостях

// Правильно
useEffect(() => {
  console.log(count);
}, [count]); // ОК

Чтобы игнорировать, можно добавить:

useEffect(() => {
  // ...
}, []); // eslint-disable-next-line react-hooks/exhaustive-deps

НО это плохая практика без серьёзной причины.

Лучшие практики

  1. Всегда указывай массив зависимостей

    • Либо пустой [] для инициализации
    • Либо с конкретными зависимостями
  2. Изучи ESLint правила для React Hooks

    {
      "extends": ["plugin:react-hooks/recommended"]
    }
    
  3. Если забыл зависимость, ESLint подскажет:

    "count" is not included in the dependency array
    
  4. Тестируй поведение в devtools

    useEffect(() => {
      console.log('Эффект выполнен');
    }, []); // Поставь точку останова и смотри когда выполняется
    

Часто задаваемый вопрос

Вопрос: Почему ESLint требует указывать все переменные в зависимостях?

Ответ: Потому что React нужно знать, когда пересчитывать эффект. Если ты используешь переменную, но не указал её в зависимостях, эффект может использовать старые значения (stale closure).

function Example() {
  const [count, setCount] = useState(0);
  
  useEffect(() => {
    setTimeout(() => {
      console.log(count); // Какой count будет тут?
    }, 3000);
  }, []); // ОШИБКА: count должен быть в зависимостях
  
  return (
    <div>
      <p>{count}</p>
      <button onClick={() => setCount(count + 1)}>Увеличить</button>
    </div>
  );
}

// Если нажать кнопку несколько раз и подождать 3 сек
// Выведет 0 (старое значение), а не текущее

Заключение

Не передавать массив зависимостей в useEffect — это обычно ОШИБКА. Эффект будет выполняться после каждого рендера, что часто приводит к бесконечным циклам и проблемам производительности. Всегда указывай массив зависимостей или пустой [] для контроля когда выполняется эффект.