Как работает return в useEffect?
Хуки
Функция, которую эффект возвращает через return, — это cleanup-функция: React вызывает её, чтобы «прибрать» за предыдущим запуском эффекта.
Когда вызывается cleanup
- Перед каждым повторным запуском эффекта (если изменились зависимости): сначала очистка старого, затем новый эффект.
- При размонтировании компонента.
useEffect(() => {
const socket = connectToRoom(roomId);
return () => socket.disconnect(); // cleanup
}, [roomId]);Последовательность при смене roomId: рендер → отключение от старой комнаты (cleanup) → подключение к новой (эффект). При размонтировании — только отключение.
Зачем нужен
- Отписки: removeEventListener, unsubscribe, disconnect.
- Таймеры: clearTimeout / clearInterval.
- Отмена запросов / защита от гонок:
useEffect(() => {
let cancelled = false;
loadUser(id).then((u) => { if (!cancelled) setUser(u); });
return () => { cancelled = true; };
}, [id]);Без cleanup ответ старого запроса может прийти позже нового и перезаписать актуальные данные; плюс setState на размонтированном компоненте — утечка логики.
Нюансы
- Cleanup «замыкает» значения того рендера, в котором эффект был создан, — отписывается именно от того, на что подписывался.
- В StrictMode (dev) React монтирует компонент, вызывает эффект, тут же cleanup и эффект снова — так проверяется, что очистка написана корректно.
- return в эффекте должен возвращать функцию (или ничего), поэтому нельзя писать
useEffect(async () => ...): async-функция возвращает Promise.
Коротко для собеседования
return в useEffect возвращает cleanup-функцию; React вызывает её перед каждым перезапуском эффекта и при размонтировании. Используется для отписок, очистки таймеров и защиты от гонок запросов. Из-за этого эффект нельзя делать async — он должен вернуть функцию, а не Promise.