> Для чего служит второй аргумент у useEffect в React (React)

Уровень: senior · Роль: frontend · Категория: Технические вопросы

Компании: EvApps, Aston

Стек: React

> Пример ответа

Короткий ответ

Второй аргумент useEffect - это массив зависимостей (dependencies array), который управляет перезапуском эффекта. Если он не указан, эффект выполняется после каждого рендера. Пустой массив [] запускает эффект только один раз при монтировании. При указании конкретных значений эффект перезапускается только при их изменении. Это ключевой механизм для контроля сайд-эффектов и предотвращения бесконечных циклов.

Подробное объяснение

useEffect - это хук для выполнения сайд-эффектов в функциональных компонентах React. Его сигнатура: useEffect(callback, dependencies?). Второй аргумент - это массив, который определяет, когда эффект должен быть повторно выполнен.

  • Без второго аргумента: эффект выполняется после каждого рендера и обновления компонента. Это может привести к проблемам производительности и бесконечным циклам, если эффект изменяет состояние.
  • Пустой массив []: эффект выполняется один раз после первого рендера (аналог componentDidMount в классовых компонентах). Очистка эффекта (если есть) выполняется при размонтировании (аналог componentWillUnmount).
  • Массив с зависимостями [dep1, dep2]: эффект выполняется после первого рендера и затем каждый раз, когда любое из значений в массиве изменяется (сравнение через Object.is). Это позволяет синхронизировать эффект с конкретными пропсами или состоянием.

React использует строгое сравнение (reference equality) для примитивов и ссылочных типов. Если зависимость - объект или функция, он будет считаться новым при каждом рендере, если не используется мемоизация (useMemo, useCallback).

На практике

На практике второй аргумент - это основной инструмент для контроля жизненного цикла эффектов. Типичные сценарии:

  • Загрузка данных: [] для однократного запроса при монтировании.
  • Подписки и event listeners: [] с функцией очистки в return.
  • Реакция на изменение пропсов: [propName] для выполнения действия при изменении конкретного значения.
  • Debounced/Throttled операции: зависимости включают только те значения, которые должны триггерить эффект.

Важно: все переменные из замыкания эффекта, которые могут измениться, должны быть в массиве зависимостей. Иначе эффект будет использовать устаревшие значения (stale closure). ESLint правило react-hooks/exhaustive-deps помогает это отслеживать.

Пример кода

JSX
import { useState, useEffect } from 'react';
function UserProfile({ userId }) {
const [user, setUser] = useState(null);
// Загрузка данных при изменении userId
useEffect(() => {
const fetchUser = async () => {
const response = await fetch(`/api/users/${userId}`);
const data = await response.json();
setUser(data);
};
fetchUser();
}, [userId]); // эффект перезапускается только при изменении userId
// Подписка на статус пользователя (один раз)
useEffect(() => {
const subscription = subscribeToUserStatus(userId, (status) => {
console.log('Status:', status);
});
return () => subscription.unsubscribe(); // очистка при размонтировании
}, []); // пустой массив - только при монтировании
return <div>{user?.name}</div>;
}

Как отвечать на собеседовании

Начни с чёткого определения: второй аргумент - массив зависимостей, управляющий перезапуском эффекта. Объясни три режима: без массива, пустой массив, массив с значениями. Подчеркни важность включения всех зависимостей для избежания багов с устаревшими данными. Упомяни про очистку эффекта и сравнение через Object.is. Если спросят про оптимизацию, скажи, что зависимости - это не про производительность, а про корректность синхронизации. Приведи пример с загрузкой данных и подпиской.

Что проверяет интервьюер

Интервьюер проверяет:

  • Понимание жизненного цикла эффектов в React (монтирование, обновление, размонтирование).
  • Знание механизма сравнения зависимостей и потенциальных проблем (stale closure, бесконечные циклы).
  • Умение правильно выбирать зависимости для разных сценариев (загрузка, подписки, анимации).
  • Осознание разницы между [] и отсутствием массива.
  • Знание правил линтера exhaustive-deps и их обоснование.

Типичные ошибки

  • Пропуск зависимостей: не включение переменных из замыкания, что приводит к использованию устаревших значений.
  • Лишние зависимости: включение функций или объектов, создаваемых при каждом рендере, что вызывает бесконечные перезапуски (нужна мемоизация).
  • Путаница с []: использование пустого массива для эффектов, которые должны реагировать на изменения пропсов.
  • Игнорирование очистки: не возврат функции очистки для подписок, таймеров или event listeners, что вызывает утечки памяти.
  • Асинхронные эффекты без обработки: не отмена запроса при размонтировании или изменении зависимостей (race condition).

> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?

Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью