Що робить cleanup-функція в useEffect()?
Вона допомагає уникнути витоків пам'яті, подвійних підписок, зайвих викликів і помилок на кшталт
"Can't perform a React state update on an unmounted component".
Визначення
Cleanup-функція - це функція, яку ти повертаєш з
useEffect, і яку React викличе автоматично:
- перед розмонтуванням компонента
- або перед наступним запуском цього ефекту (якщо залежності змінилися)
Синтаксис
useEffect(() => {
// Тіло ефекту - виконується при монтуванні або оновленні
return () => {
// Cleanup - виконується при розмонтуванні або перед новим ефектом
};
}, [dependencies]);Коли саме вона викликається
| Сценарій | Коли викличеться cleanup |
|---|---|
| Компонент розмонтується | Один раз, перед видаленням з DOM |
| Змінилася залежність ефекту | Спочатку cleanup старого ефекту, потім новий запуск |
| Компонент перерендерився, але залежності не змінилися | Cleanup не викликається |
Приклад 1 - очищення таймера
useEffect(() => {
const id = setInterval(() => {
console.log('tick');
}, 1000);
return () => {
clearInterval(id); // Очищення при розмонтуванні
console.log('очищено');
};
}, []); // [] → ефект спрацює один разЩо станеться:
- При монтуванні створюється таймер.
- При розмонтуванні (видаленні компонента) cleanup зупинить інтервал.
Приклад 2 - відписка від подій
useEffect(() => {
const handleResize = () => console.log(window.innerWidth);
window.addEventListener('resize', handleResize);
return () => {
window.removeEventListener('resize', handleResize); // очищення
};
}, []);Якщо не зробити cleanup, обробник залишиться активним навіть після видалення компонента - витік пам'яті.
Приклад 3 - при зміні залежностей
useEffect(() => {
console.log('Запуск ефекту для user:', userId);
return () => {
console.log('Очищення перед новим ефектом user:', userId);
};
}, [userId]);Що станеться:
- При зміні
userIdReact спочатку викличе cleanup старого ефекту, а потім запустить новий ефект. - Це важливо для скасування старих запитів, закриття з'єднань тощо.
Приклад 4 - скасування асинхронних запитів
useEffect(() => {
const controller = new AbortController();
fetch(`/api/user/${userId}`, { signal: controller.signal })
.then(res => res.json())
.then(console.log)
.catch(console.error);
return () => {
controller.abort(); // скасовуємо запит, якщо компонент розмонтується
};
}, [userId]);Якщо користувач швидко перемкне userId, старий запит скасується,
і новий ефект почнеться з чистого стану.
Чому cleanup важливий
Без cleanup-функцій можливі:
-
Витоки пам'яті (таймери, підписки, WebSocket, слухачі)
-
Дублювання ефектів при оновленнях
-
Помилки на кшталт:
"Can't perform a state update on an unmounted component"
Аналогія в класових компонентах
| Функціональні компоненти | Класові компоненти |
|---|---|
return () => {...} всередині useEffect() | componentWillUnmount() |
useEffect(() => {...}, [deps]) | componentDidUpdate() + componentWillUnmount() разом |
Міні-таблиця поведінки
| Дія | Викликається ефект | Викликається cleanup |
|---|---|---|
| Монтування | Так | Ні |
| Оновлення зі зміною залежностей | Так | Так (перед цим) |
| Оновлення без зміни залежностей | Ні | Ні |
| Розмонтування | Ні | Так |
Підсумок
Cleanup-функція в
useEffect()- це механізм очищення побічних ефектів, який React викликає перед видаленням компонента або перед повторним виконанням ефекту.
Вона:
- звільняє ресурси (таймери, події, сокети),
- запобігає витокам,
- гарантує, що компонент завжди працює у "чистому" стані.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.