> Какие жизненные циклы есть у классовых компонентов и как они реализованы в функциональных (React)

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

Компании: Сбер

Стек: React

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

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

У классовых компонентов три фазы жизненного цикла: монтирование (constructor, render, componentDidMount), обновление (shouldComponentUpdate, render, componentDidUpdate) и размонтирование (componentWillUnmount). В функциональных компонентах они реализованы через хуки: useState и useEffect с массивами зависимостей имитируют componentDidMount ([]), componentDidUpdate (без зависимостей или с конкретными) и componentWillUnmount (return cleanup). useMemo и useCallback заменяют shouldComponentUpdate.

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

Классовые компоненты React имеют четко определенные методы жизненного цикла, которые вызываются в определенные моменты:

  • Монтирование: constructor → static getDerivedStateFromProps → render → componentDidMount
  • Обновление: static getDerivedStateFromProps → shouldComponentUpdate → render → getSnapshotBeforeUpdate → componentDidUpdate
  • Размонтирование: componentWillUnmount

Функциональные компоненты используют хуки для эмуляции этих фаз:

  • useEffect с [] - выполняется после первого рендера, аналог componentDidMount
  • useEffect без зависимостей - выполняется после каждого рендера, аналог componentDidUpdate (но не идентичен, так как вызывается после рендера, а не до)
  • useEffect с return cleanup - cleanup функция вызывается при размонтировании, аналог componentWillUnmount
  • useMemo - мемоизация вычислений, частично заменяет shouldComponentUpdate
  • useCallback - мемоизация функций

Ключевое отличие: в функциональных компонентах эффекты объединяют несколько фаз в один хук, что упрощает код, но требует понимания порядка выполнения. useEffect всегда выполняется после рендера, в то время как componentDidUpdate вызывается синхронно после обновления.

На практике

Для замены componentDidMount используйте useEffect с пустым массивом зависимостей. Для componentDidUpdate - useEffect с конкретными зависимостями или без них. Для componentWillUnmount - return функцию внутри useEffect. Избегайте использования useEffect без зависимостей для логики, которая должна выполняться только при монтировании - это приведет к повторным вызовам.

Для оптимизации производительности используйте useMemo и useCallback вместо shouldComponentUpdate, но помните, что они не предотвращают рендер, а только мемоизируют значения. Для предотвращения лишних рендеров используйте React.memo.

Пример кода

JSX
// Классовый компонент
class UserProfile extends React.Component {
componentDidMount() {
fetchUser(this.props.id);
}
componentDidUpdate(prevProps) {
if (prevProps.id !== this.props.id) {
fetchUser(this.props.id);
}
}
componentWillUnmount() {
cleanup();
}
render() {
return <div>{this.props.name}</div>;
}
}
// Функциональный компонент
function UserProfile({ id, name }) {
useEffect(() => {
fetchUser(id);
return () => cleanup();
}, [id]); // выполняется при монтировании и при изменении id
return <div>{name}</div>;
}

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

Начните с перечисления фаз жизненного цикла классовых компонентов, затем объясните, как каждый метод заменяется хуками. Упомяните, что useEffect объединяет componentDidMount, componentDidUpdate и componentWillUnmount. Подчеркните разницу в порядке выполнения: в классовом компоненте методы вызываются синхронно, в функциональном - асинхронно после рендера. Приведите пример с зависимостями и cleanup функцией.

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

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

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

  • Использование useEffect без зависимостей для логики, которая должна выполняться только при монтировании - это приводит к повторным вызовам при каждом ререндере
  • Путаница между componentDidUpdate и useEffect: useEffect не блокирует рендер, а выполняется после него
  • Забывание cleanup функции для отписки от событий или отмены запросов
  • Использование useMemo и useCallback без необходимости - это добавляет overhead и усложняет код
  • Попытка напрямую заменить shouldComponentUpdate на useEffect - это разные концепции

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

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