← Назад к вопросам
Как в функциональном компоненте можно реализовать Unmount?
1.0 Junior🔥 71 комментариев
#React
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Unmount в функциональных компонентах React
Что такое Unmount
Unmount - это момент, когда компонент удаляется из DOM (снимается со страницы). Это противоположно Mount (когда компонент впервые появляется на странице).
Жизненный цикл компонента
// Функциональный компонент:
function MyComponent() {
// 1. RENDER (инициализация переменных, вычисления)
console.log('Компонент рендерится');
useEffect(() => {
// 2. MOUNT (компонент добавлен в DOM)
console.log('Компонент смонтирован');
// 3. UNMOUNT (cleanup функция)
return () => {
console.log('Компонент удаляется');
};
}, []); // пустой массив = только при mount/unmount
return <div>Hello</div>;
}
Реализация Unmount через useEffect
В функциональных компонентах используется return функция в useEffect:
function Timer() {
useEffect(() => {
console.log('Компонент смонтирован, запускаем таймер');
// Запустить интервал
const intervalId = setInterval(() => {
console.log('Tick');
}, 1000);
// UNMOUNT: cleanup функция
return () => {
console.log('Компонент удаляется, очищаем интервал');
clearInterval(intervalId);
};
}, []); // [] = только один раз при mount
return <div>Timer running...</div>;
}
Практические примеры
1. Очистка подписок (Subscriptions)
function WebSocketComponent() {
useEffect(() => {
// MOUNT: подключиться
const ws = new WebSocket('wss://api.example.com');
ws.onmessage = (event) => {
console.log('Сообщение:', event.data);
};
// UNMOUNT: отключиться
return () => {
console.log('Отключаемся от WebSocket');
ws.close();
};
}, []);
return <div>WebSocket connected</div>;
}
2. Удаление Event Listeners
function ResizeHandler() {
useEffect(() => {
// MOUNT: добавить слушатель
const handleResize = () => {
console.log('Окно изменилось:', window.innerWidth);
};
window.addEventListener('resize', handleResize);
// UNMOUNT: удалить слушатель
return () => {
console.log('Удаляем слушатель resize');
window.removeEventListener('resize', handleResize);
};
}, []);
return <div>Window size tracker</div>;
}
3. Отмена API запросов
function DataFetcher() {
const [data, setData] = useState(null);
useEffect(() => {
// MOUNT: создать AbortController для отмены запроса
const abortController = new AbortController();
fetch('/api/data', {signal: abortController.signal})
.then(r => r.json())
.then(data => setData(data))
.catch(err => {
if (err.name === 'AbortError') {
console.log('Запрос отменён при unmount');
}
});
// UNMOUNT: отменить запрос если компонент удалён
return () => {
console.log('Компонент удаляется, отменяем fetch');
abortController.abort();
};
}, []);
return <div>{data ? JSON.stringify(data) : 'Loading...'}</div>;
}
4. Очистка таймеров (setTimeout/setInterval)
function DelayedAction() {
useEffect(() => {
console.log('Запланировали действие на 5 секунд');
const timeoutId = setTimeout(() => {
console.log('Действие выполнено!');
}, 5000);
// UNMOUNT: отменить таймер если компонент удалён ДО срока
return () => {
console.log('Компонент удалён, отменяем таймер');
clearTimeout(timeoutId);
};
}, []);
return <div>Ожидание 5 секунд...</div>;
}
Множественные useEffect
function ComplexComponent() {
useEffect(() => {
console.log('Effect 1: MOUNT');
return () => console.log('Effect 1: UNMOUNT');
}, []);
useEffect(() => {
console.log('Effect 2: MOUNT');
return () => console.log('Effect 2: UNMOUNT');
}, []);
return <div>Component</div>;
}
// При монтировании:
// Effect 1: MOUNT
// Effect 2: MOUNT
// При размонтировании:
// Effect 1: UNMOUNT
// Effect 2: UNMOUNT
// (в обратном порядке)
Сравнение с Class-компонентами
// CLASS КОМПОНЕНТ (старый способ)
class MyComponent extends React.Component {
componentDidMount() {
console.log('Компонент смонтирован');
}
componentWillUnmount() {
console.log('Компонент удаляется');
}
render() {
return <div>Hello</div>;
}
}
// ФУНКЦИОНАЛЬНЫЙ КОМПОНЕНТ (современный способ)
function MyComponent() {
useEffect(() => {
console.log('Компонент смонтирован');
return () => {
console.log('Компонент удаляется');
};
}, []);
return <div>Hello</div>;
}
// Результат идентичен, но функциональный компонент проще
Почему важно очищать ресурсы
// ПЛОХО - утечка памяти
function BadComponent() {
useEffect(() => {
const interval = setInterval(() => {
console.log('Tick');
}, 1000);
// Забыли очистить interval!
// Если компонент монтируется и размонтируется 10 раз,
// будет 10 интервалов, работающих одновременно
}, []);
return <div>Component</div>;
}
// ХОРОШО - правильная очистка
function GoodComponent() {
useEffect(() => {
const interval = setInterval(() => {
console.log('Tick');
}, 1000);
return () => clearInterval(interval); // очистили
}, []);
return <div>Component</div>;
}
Пример: Полноценный компонент
function ChatWindow({userId}) {
const [messages, setMessages] = useState([]);
const [isConnected, setIsConnected] = useState(false);
useEffect(() => {
// MOUNT
const ws = new WebSocket(`wss://chat.example.com/${userId}`);
ws.onopen = () => {
setIsConnected(true);
console.log('WebSocket подключён');
};
ws.onmessage = (event) => {
const msg = JSON.parse(event.data);
setMessages(prev => [...prev, msg]);
};
ws.onerror = (error) => {
console.error('WebSocket ошибка:', error);
};
// UNMOUNT: очистка
return () => {
console.log('WebSocket закрывается');
setIsConnected(false);
ws.close();
};
}, [userId]); // пересоздать если userId изменился
return (
<div>
<p>Статус: {isConnected ? 'Подключён' : 'Отключён'}</p>
<ul>
{messages.map((msg, i) => (
<li key={i}>{msg.text}</li>
))}
</ul>
</div>
);
}
Вывод
Unmount в функциональных компонентах реализуется через return функцию в useEffect. Это критично для:
- Очистки таймеров и интервалов
- Отписки от событий
- Закрытия WebSocket подключений
- Отмены API запросов
- Предотвращения утечек памяти
Это один из самых важных паттернов в React!