> Как работает useEffect хук в React (React)

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

Компании: ADV/web-engineering, Иннотех, Kodix, EPAM, Exness, Исходный Код

Стек: React

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

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

useEffect - это хук для выполнения side effects в функциональных компонентах React. Он принимает callback (effect) и массив зависимостей. Effect выполняется после рендера, а cleanup - при размонтировании или перед повторным запуском. Без зависимостей - после каждого рендера, с пустым массивом - один раз при монтировании, с конкретными значениями - при их изменении.

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

useEffect решает проблему синхронизации компонента с внешними системами (API, DOM, таймеры, подписки). Он заменяет методы жизненного цикла классовых компонентов: componentDidMount, componentDidUpdate, componentWillUnmount.

Механизм работы:

  • После каждого рендера React проверяет зависимости effect (сравнение через Object.is).
  • Если зависимости изменились, сначала выполняется cleanup предыдущего effect (если есть), затем запускается текущий effect.
  • Cleanup возвращается из effect-функции и гарантирует корректное освобождение ресурсов.

Важные нюансы:

  • Effect выполняется асинхронно, после того как браузер отрисовал изменения (в отличие от useLayoutEffect).
  • Массив зависимостей должен включать все переменные из effect, иначе возможны stale closures.
  • Для асинхронных операций внутри effect нужно обрабатывать race conditions (например, через флаг отмены).
  • useEffect не блокирует рендер, что улучшает производительность, но может вызвать визуальные скачки (тогда нужен useLayoutEffect).

На практике

Сеньор должен понимать trade-offs использования useEffect:

  • Избегать избыточных эффектов - часто логику можно вынести в обработчики событий или кастомные хуки.
  • Для вычислений на основе пропсов/стейта лучше использовать useMemo или useCallback.
  • При работе с формами предпочтительнее controlled components с синхронным обновлением стейта.
  • Для анимаций и измерений DOM - useLayoutEffect (синхронный, до отрисовки).

Паттерны:

  • Debounce/throttle запросов через useEffect с таймерами.
  • Подписка на WebSocket с корректным cleanup.
  • Загрузка данных с обработкой отмены запроса через AbortController.

Пример кода

JSX
function UserProfile({ userId }) {
const [user, setUser] = useState(null);
const [error, setError] = useState(null);
useEffect(() => {
// Флаг для предотвращения race condition
let cancelled = false;
const controller = new AbortController();
async function fetchUser() {
try {
const response = await fetch(`/api/users/${userId}`, {
signal: controller.signal
});
const data = await response.json();
if (!cancelled) {
setUser(data);
}
} catch (err) {
if (err.name !== 'AbortError' && !cancelled) {
setError(err.message);
}
}
}
fetchUser();
// Cleanup: отмена запроса и сброс флага
return () => {
cancelled = true;
controller.abort();
};
}, [userId]);
if (error) return <div>Error: {error}</div>;
if (!user) return <div>Loading...</div>;
return <div>{user.name}</div>;
}

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

Начни с определения и базового механизма. Затем переходи к деталям: порядок выполнения, сравнение зависимостей, cleanup. Покажи понимание проблем (stale closures, race conditions) и способы их решения. Упомяни отличия от useLayoutEffect и когда что выбирать. Хорошо привести реальный кейс из опыта, где useEffect решил конкретную проблему.

Не заучивай - демонстрируй понимание через примеры и рассуждения о trade-offs.

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

  • Понимание lifecycle и синхронизации с внешним миром.
  • Умение работать с асинхронностью и побочными эффектами.
  • Знание проблем (stale closure, race condition, memory leaks) и способов их избежать.
  • Способность выбирать правильный инструмент (useEffect vs useLayoutEffect vs обработчики).
  • Опыт написания чистого, поддерживаемого кода с эффектами.

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

  • Пропуск зависимостей в массиве (особенно функций или объектов).
  • Отсутствие cleanup для подписок, таймеров, запросов.
  • Использование useEffect для синхронных вычислений (лучше useMemo).
  • Забывание обработать ошибки в асинхронных эффектах.
  • Создание бесконечного цикла из-за изменения стейта в effect без контроля зависимостей.
  • Использование async непосредственно в effect-функции (она возвращает Promise, а не cleanup).

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

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