Gernar
React и Next.js

Что знаешь о cleanup у useEffect

Разбор вопроса «Что знаешь о cleanup у useEffect» для Frontend Developer: что проверяет интервьюер, ключевые тезисы, практические примеры и частые ошибки.

Вопрос

Что знаешь о cleanup у useEffect

Профессия

Frontend Developer

Что хочет услышать интервьюер

Интервьюер хочет убедиться, что кандидат понимает важность cleanup для управления побочными эффектами, знает синтаксис и сценарии его применения (например, отписка от событий, отмена таймеров). Также важно показать понимание жизненного цикла useEffect и последствий отсутствия cleanup.

Ключевые тезисы

  • Cleanup в useEffect — это функция, которая вызывается перед удалением компонента из DOM или перед следующим выполнением эффекта, чтобы избежать утечек памяти или побочных эффектов.
  • Cleanup особенно важен для отписки от событий, таймеров (setTimeout, setInterval) или запросов (fetch, WebSocket), чтобы избежать их выполнения после размонтирования компонента.
  • Функция cleanup возвращается из callback-функции, переданной в useEffect. Например: return () => clearInterval(intervalId);.
  • Cleanup выполняется перед каждым новым рендером, если указаны зависимости, или перед размонтированием компонента, если зависимости пусты (аналог componentWillUnmount в классовых компонентах).
  • Игнорирование cleanup может привести к утечкам памяти, ошибкам при попытке обновления состояния размонтированного компонента или дублированию подписок/таймеров.

Подробный ответ

Cleanup в useEffect — это функция, которая вызывается перед удалением компонента из DOM или перед следующим выполнением эффекта. Она позволяет избежать утечек памяти, ошибок при обновлении состояния размонтированного компонента и других побочных эффектов. Например, если вы подписываетесь на событие или запускаете таймер, необходимо отписаться или очистить таймер при размонтировании компонента, чтобы избежать выполнения этих действий после того, как компонент больше не существует. Cleanup также выполняется перед каждым новым рендером, если указаны зависимости, что позволяет корректно обновлять ресурсы. Без cleanup возможны утечки памяти, ошибки и дублирование подписок или таймеров.

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

Пример 1

Пример с таймером: `useEffect(() => { const intervalId = setInterval(() => { console.log('Таймер сработал'); }, 1000); return () => clearInterval(intervalId); }, []);`. Здесь cleanup очищает таймер перед размонтированием компонента.

Пример 2

Пример с подпиской на событие: `useEffect(() => { const handleResize = () => { console.log('Размер окна изменился'); }; window.addEventListener('resize', handleResize); return () => window.removeEventListener('resize', handleResize); }, []);`. Cleanup отписывается от события при размонтировании компонента.

Пример 3

Пример с асинхронным запросом: `useEffect(() => { let isMounted = true; fetch('https://api.example.com/data').then(response => { if (isMounted) { setData(response.data); } }); return () => { isMounted = false; }; }, []);`. Cleanup предотвращает обновление состояния размонтированного компонента.

Частые ошибки

  • Игнорирование cleanup для таймеров или подписок, что приводит к утечкам памяти и ошибкам.
  • Использование асинхронных операций в cleanup, что может привести к непредсказуемым результатам.
  • Забывают указать зависимости в useEffect, что может вызывать ненужные повторные выполнения эффекта и cleanup.

Связанные темы

  • Жизненный цикл компонентов в React
  • Асинхронные операции в JavaScript
  • Управление состоянием в React
  • Сравнение useEffect с методами жизненного цикла в классовых компонентах

Follow-up вопросы

Можешь привести пример, когда cleanup предотвращает утечку памяти?

Уровень: basic

Например, при подписке на WebSocket или события. Если не отписаться в cleanup, ссылки останутся в памяти, а обработчики будут вызываться для несуществующего компонента.

Что произойдет, если не использовать cleanup для setInterval?

Уровень: intermediate

Таймер продолжит работать после размонтирования компонента, что может вызвать ошибки при попытке обновить состояние несуществующего компонента или излишнюю нагрузку.

Как cleanup связан с зависимостями useEffect?

Уровень: intermediate

Cleanup выполняется перед каждым новым вызовом эффекта, если зависимости изменились, или перед размонтированием. Это позволяет 'очищать' предыдущий эффект перед применением нового.

Можно ли использовать асинхронные операции в cleanup?

Уровень: advanced

Нет, cleanup должен быть синхронным. Асинхронные операции нужно завершать до cleanup, например, через отмену промиса (AbortController) или флаги.

Как cleanup помогает избежать 'race conditions' в запросах?

Уровень: advanced

Cleanup может отменять pending-запросы (через AbortController), предотвращая обновление состояния устаревшими данными, если компонент размонтирован или запрос перезапущен.

Содержание