- Главная
- Javascript
- Жизненный цикл React: mount, update, unmount
Жизненный цикл React: mount, update, unmount
Содержание
- Введение: что такое жизненный цикл
- Жизненный цикл в функциональных компонентах (хуки)
- Хук
useEffect— главный инструмент - Фаза 1. Монтирование (Mounting)
- Фаза 2. Обновление (Updating)
- Фаза 3. Размонтирование (Unmounting)
useEffectс зависимостями — подробно- Частые сценарии использования
useEffect - Сравнение с классовыми компонентами
useEffectи асинхронные операции- Частые ошибки новичков
- Итог (что мы узнали)
- Задание для закрепления (на 10–12 минут)
- Что дальше?
Цель урока: понять, что происходит с React-компонентом на каждом этапе его существования: от создания до удаления. Научиться выполнять код в нужные моменты — при загрузке данных, при обновлении или перед тем, как компонент исчезает с экрана.
Введение: что такое жизненный цикл
Каждый компонент в React проходит через три основные фазы:
| Фаза | Что происходит | Что можно делать |
|---|---|---|
| Монтирование (Mounting) | Компонент появляется на экране | Загрузить данные, подписаться на события |
| Обновление (Updating) | Компонент перерисовывается (изменился state или props) | Реагировать на изменения, обновлять DOM |
| Размонтирование (Unmounting) | Компонент исчезает с экрана | Отписаться от событий, очистить таймеры |
Главная мысль: у каждого компонента есть «жизненный цикл» — моменты, когда он рождается, обновляется и умирает. На этих этапах можно выполнять нужные действия.
Жизненный цикл в функциональных компонентах (хуки)
В современных React-приложениях (с хуками) жизненным циклом управляет хук useEffect.
Важно: в функциональных компонентах нет отдельных методов, как в классовых. Всё делается через useEffect с разными зависимостями.
Сопоставление классовых методов и хуков
| Классовый компонент | Функциональный компонент (хуки) |
|---|---|
componentDidMount |
useEffect(() => {...}, []) |
componentDidUpdate |
useEffect(() => {...}, [deps]) |
componentWillUnmount |
useEffect(() => { return () => {...} }, []) |
Хук useEffect — главный инструмент
Синтаксис:
useEffect(() => {
// Код, который выполняется при монтировании и обновлении
return () => {
// Очистка (выполняется при размонтировании)
};
}, [зависимости]);
Три варианта использования:
| Вариант | Код | Когда выполняется |
|---|---|---|
| Без зависимостей | useEffect(() => {...}) |
При каждом рендере |
| Пустой массив | useEffect(() => {...}, []) |
Один раз при монтировании |
| С зависимостями | useEffect(() => {...}, [count]) |
При монтировании и при изменении count |
Фаза 1. Монтирование (Mounting)
Что происходит:
- React создаёт DOM-элементы
- Вставляет их на страницу
- Выполняется код после рендера
Как это выглядит в коде:
import { useEffect } from 'react';
function UserProfile({ userId }) {
useEffect(() => {
// Код выполняется один раз после первого рендера
console.log('Компонент смонтирован на страницу');
// Загружаем данные пользователя
fetchUserData(userId);
// Подписываемся на события
const handleResize = () => console.log('Окно изменено');
window.addEventListener('resize', handleResize);
// Возвращаем функцию очистки (будет вызвана при размонтировании)
return () => {
console.log('Компонент будет удалён');
window.removeEventListener('resize', handleResize);
};
}, []); // Пустой массив = только при монтировании
return <div>Профиль пользователя</div>;
}
Типичные задачи при монтировании:
- Загрузка данных с сервера (API-запросы)
- Подписка на события (resize, scroll, WebSocket)
- Настройка таймеров (setInterval, setTimeout)
- Работа с DOM (фокус, размеры)
Оживи свой сайт. Освой JavaScript!
Статичная верстка — это только скелет. Наш онлайн-курс "JavaScript с нуля до профи" даст твоим страницам мышцы и нервы. Научись создавать слайдеры, формы, интерактивные карты и получать данные с сервера.
От теории — к реальным скриптам в твоём портфолио.
Фаза 2. Обновление (Updating)
Что происходит:
- Меняется
stateилиprops - React перерисовывает компонент
- Выполняется эффект (если зависимости изменились)
Как это выглядит в коде:
function Counter() {
const [count, setCount] = useState(0);
const [doubledCount, setDoubledCount] = useState(0);
useEffect(() => {
// Код выполняется при каждом изменении count
console.log(`Счёт изменился: ${count}`);
setDoubledCount(count * 2);
}, [count]); // Выполняется только когда count меняется
return (
<div>
<p>Счёт: {count}</p>
<p>Удвоенный счёт: {doubledCount}</p>
<button onClick={() => setCount(count + 1)}>+1</button>
</div>
);
}
Типичные задачи при обновлении:
- Реагировать на изменение
props - Пересчитывать производные данные
- Обновлять DOM в зависимости от изменений
- Отправлять аналитику
Фаза 3. Размонтирование (Unmounting)
Что происходит:
- Компонент удаляется из DOM
- Выполняется функция очистки
Как это выглядит в коде:
function Timer() {
const [seconds, setSeconds] = useState(0);
useEffect(() => {
// Настраиваем таймер при монтировании
const interval = setInterval(() => {
setSeconds(prev => prev + 1);
}, 1000);
// Очищаем таймер при размонтировании
return () => {
clearInterval(interval);
console.log('Таймер остановлен');
};
}, []);
return <p>Прошло секунд: {seconds}</p>;
}
Типичные задачи при размонтировании:
- Остановка таймеров (
setInterval,setTimeout) - Отписка от событий (
removeEventListener) - Закрытие соединений (
WebSocket) - Отмена запросов (
AbortController) - Очистка подписок
useEffect с зависимостями — подробно
Пустой массив [] — один раз при монтировании:
useEffect(() => {
// Выполняется один раз
console.log('Только при монтировании');
}, []);
Массив с переменными — при их изменении:
useEffect(() => {
console.log(`Изменился пропс userId: ${userId}`);
}, [userId]);
Несколько зависимостей:
useEffect(() => {
console.log(`userId или userRole изменились`);
}, [userId, userRole]);
Без массива — при каждом рендере (используй осторожно!):
useEffect(() => {
console.log('Выполняется при каждом рендере');
}); // Нет массива зависимостей
Частые сценарии использования useEffect
1. Загрузка данных при монтировании:
function UserList() {
const [users, setUsers] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
const fetchUsers = async () => {
const response = await fetch('/api/users');
const data = await response.json();
setUsers(data);
setLoading(false);
};
fetchUsers();
}, []); // Загружаем только один раз
if (loading) return <p>Загрузка...</p>;
return <div>{users.map(user => <p key={user.id}>{user.name}</p>)}</div>;
}
2. Подписка на событие с очисткой:
function WindowWidth() {
const [width, setWidth] = useState(window.innerWidth);
useEffect(() => {
const handleResize = () => setWidth(window.innerWidth);
window.addEventListener('resize', handleResize);
return () => {
window.removeEventListener('resize', handleResize);
};
}, []);
return <p>Ширина окна: {width}px</p>;
}
3. Автосохранение при изменении данных:
function NoteEditor() {
const [content, setContent] = useState('');
useEffect(() => {
// Автосохраняем каждые 3 секунды при изменении content
const timer = setTimeout(() => {
localStorage.setItem('note', content);
console.log('Заметка сохранена');
}, 3000);
return () => clearTimeout(timer);
}, [content]);
return <textarea value={content} onChange={(e) => setContent(e.target.value)} />;
}
Сравнение с классовыми компонентами
Для понимания legacy-кода:
class UserProfile extends React.Component {
// 1. Монтирование
componentDidMount() {
console.log('Компонент смонтирован');
this.loadData();
}
// 2. Обновление
componentDidUpdate(prevProps, prevState) {
if (this.props.userId !== prevProps.userId) {
console.log('userId изменился');
this.loadData();
}
}
// 3. Размонтирование
componentWillUnmount() {
console.log('Компонент будет удалён');
clearInterval(this.interval);
}
loadData() {
// Загрузка данных
}
render() {
return <div>Профиль</div>;
}
}
useEffect и асинхронные операции
Важно: useEffect не может быть асинхронным напрямую:
❌ Неправильно:
useEffect(async () => {
const data = await fetchData(); // Ошибка!
}, []);
✅ Правильно (создаём функцию внутри):
useEffect(() => {
const fetchData = async () => {
const response = await fetch('/api/data');
const data = await response.json();
setData(data);
};
fetchData();
}, []);
✅ Или с IIFE (немедленно вызываемая функция):
useEffect(() => {
(async () => {
const data = await fetchData();
setData(data);
})();
}, []);
Частые ошибки новичков
| Ошибка | Почему | Исправление |
|---|---|---|
| Забывают про очистку | Таймеры/подписки продолжают работать | Всегда возвращай функцию очистки |
| Пустой массив при использовании props | Не реагирует на изменения | Добавь props в зависимости |
| Бесконечный цикл | Обновляешь state без зависимостей | Добавь зависимости или проверь логику |
| Асинхронный useEffect напрямую | async не поддерживается |
Создай функцию внутри |
| Используют useEffect для всего | Избыточное количество эффектов | Используй только когда нужно |
Итог (что мы узнали)
| Что узнали | Как это работает |
|---|---|
| Жизненный цикл | Монтирование → Обновление → Размонтирование |
useEffect |
Главный хук для управления жизненным циклом |
Пустой массив [] |
Выполнить один раз при монтировании |
| Зависимости | Выполнять при изменении переменных |
| Функция очистки | Выполняется при размонтировании |
| Асинхронные операции | Создавать функцию внутри useEffect |
Задание для закрепления (на 10–12 минут)
Создай компонент UserDataFetcher, который:
- При монтировании загружает данные пользователя по
userId(используйsetTimeoutдля имитации запроса на 1 секунду) - Показывает текст «Загрузка…» во время загрузки
- После загрузки показывает: имя, email, возраст
- При изменении
userId(передаётся черезprops) — перезагружает данные - При размонтировании компонента отменяет запрос (используй
AbortControllerили флаг)
Дополнительно: Добавь кнопку «Обновить», которая перезагружает данные с показом загрузки.
Проверка: Меняй userId в родительском компоненте и убедись, что данные обновляются. Добавь кнопку «Удалить компонент», чтобы проверить размонтирование.
Что дальше?
В следующем уроке разберём Lists and Keys — как работать с массивами данных в React. Ты научишься рендерить списки, добавлять и удалять элементы, правильно использовать ключи (key) и оптимизировать отображение больших данных. Это один из самых частых сценариев в реальных приложениях.