Как устроен жизненный цикл компонента?
Жизненный цикл компонента в React и React Native — это набор этапов, через которые проходит компонент от момента его создания до удаления с экрана. Понимание жизненного цикла особенно важно для управления состоянием, запросами к API, подписками, анимациями, кешированием и освобождением ресурсов.
Существует два типа компонентов: классовые и функциональные. У каждого из них есть своя модель жизненного цикла:
-
Классовые компоненты используют специальные методы (componentDidMount, componentDidUpdate и т. д.).
-
Функциональные компоненты используют хуки (useEffect, useLayoutEffect, useState и др.), чтобы имитировать поведение жизненного цикла.
Жизненный цикл классового компонента
Условно делится на 3 фазы:
1. Инициализация
Происходит при создании экземпляра компонента.
-
constructor(props)
-
Вызывается первым.
-
Используется для инициализации состояния через this.state = {}.
-
Также можно привязывать методы: this.handleClick = this.handleClick.bind(this);
-
2. Монтирование
Компонент добавляется в DOM (на экран).
-
static getDerivedStateFromProps(props, state)
-
Редко используется.
-
Синхронизирует состояние с props перед рендером.
-
Не имеет доступа к this.
-
-
render()
-
Обязательный метод.
-
Возвращает JSX-разметку.
-
Не должен изменять состояние или вызывать побочные эффекты.
-
-
componentDidMount()
-
Вызывается один раз после первого рендера.
-
Подходит для запросов к API, подписок, инициализации таймеров.
-
Часто используется для загрузки данных.
-
3. Обновление
Компонент может обновиться, если:
-
Изменились props
-
Изменилось state
-
Был вызван forceUpdate()
Методы:
-
static getDerivedStateFromProps()
-
shouldComponentUpdate(nextProps, nextState)
- Позволяет оптимизировать рендер, вернув false, если обновление не требуется.
-
render()
-
getSnapshotBeforeUpdate(prevProps, prevState)
- Возвращает snapshot (например, позицию прокрутки) перед обновлением DOM.
-
componentDidUpdate(prevProps, prevState, snapshot)
-
Вызывается после обновления.
-
Используется для работы с DOM, повторных запросов на основе новых props и пр.
-
4. Размонтирование
Компонент удаляется из DOM.
- componentWillUnmount()
- Подходит для отмены подписок, очистки таймеров и освобождения ресурсов.
Пример жизненного цикла в классовом компоненте
class ExampleComponent extends React.Component {
constructor(props) {
super(props);
this.state = { count: 0 };
}
componentDidMount() {
console.log('Компонент смонтирован');
}
componentDidUpdate(prevProps, prevState) {
if (prevState.count !== this.state.count) {
console.log('Счётчик обновлён');
}
}
componentWillUnmount() {
console.log('Компонент удалён');
}
render() {
return (
<Button
title="Увеличить"
onPress={() => this.setState({ count: this.state.count + 1 })}
/>
);
}
}
Жизненный цикл функционального компонента с хуками
В функциональных компонентах жизненный цикл реализуется с помощью хука useEffect.
useEffect как componentDidMount
useEffect(() => {
console.log('Компонент смонтирован');
}, \[\]);
Пустой массив зависимостей означает, что эффект выполнится один раз после монтирования.
useEffect как componentDidUpdate
useEffect(() => {
console.log('state изменился');
}, \[state\]);
Хук с зависимостями выполняется каждый раз, когда указанные значения изменяются.
useEffect как componentWillUnmount
useEffect(() => {
const subscription = someEvent.addListener(() => {});
return () => {
subscription.remove(); // очистка
console.log('Компонент размонтирован');
};
}, \[\]);
Функция, возвращаемая из useEffect, вызывается при размонтировании компонента или перед следующей активацией эффекта.
useEffect комбинирует componentDidMount, componentDidUpdate и componentWillUnmount
Пример:
useEffect(() => {
console.log('Сработал эффект');
return () => {
console.log('Очистка при размонтировании или обновлении');
};
}, \[count\]);
Алгоритм вызовов жизненного цикла
Для классовых компонентов:
-
constructor
-
getDerivedStateFromProps
-
render
-
componentDidMount
обновление:
-
getDerivedStateFromProps
-
shouldComponentUpdate
-
render
-
getSnapshotBeforeUpdate
-
componentDidUpdate
размонтирование:
- componentWillUnmount
Визуальное представление жизненного цикла
\[ constructor \]
↓
\[ getDerivedStateFromProps \]
↓
\[ render \]
↓
\[ componentDidMount \] ← монтирование завершено
↓
(пользователь взаимодействует, меняются props/state)
↓
\[ getDerivedStateFromProps \]
\[ shouldComponentUpdate \]
↓
\[ render \]
↓
\[ getSnapshotBeforeUpdate \]
↓
\[ componentDidUpdate \]
↓
\[ componentWillUnmount \] ← при удалении
Жизненный цикл и асинхронные операции
Примеры задач, которые часто обрабатываются в componentDidMount или useEffect:
-
Получение данных с API (fetch, axios)
-
Установка слушателей событий (например, Keyboard, Dimensions)
-
Запуск анимаций (Animated.timing)
-
Подключение к WebSocket или Firebase
Важно: при использовании асинхронных функций в useEffect нельзя напрямую делать async в useEffect, лучше использовать вложенную функцию:
useEffect(() => {
const fetchData = async () => {
const result = await fetch('...');
const data = await result.json();
setData(data);
};
fetchData();
}, \[\]);
Частые ошибки и замечания
-
Никогда не вызывайте setState в render, это вызовет бесконечный цикл.
-
componentDidMount вызывается только один раз, даже если props изменяются.
-
В useEffect, если вы не укажете массив зависимостей, эффект будет вызываться после каждого рендера.
-
Если вы используете setInterval или setTimeout, не забудьте их очистить в componentWillUnmount или return () => {...} в useEffect.
Жизненный цикл компонента — это ключевой механизм React и React Native, позволяющий управлять поведением компонентов на разных этапах их существования. Он охватывает монтирование, обновление и размонтирование, и на каждом этапе разработчик может внедрять собственную логику. Понимание этого процесса особенно важно при работе с состоянием, асинхронными запросами, очисткой ресурсов и оптимизацией производительности.