← Назад к вопросам

Как отследить размонтирование функционального компонента?

1.0 Junior🔥 121 комментариев
#React

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI3 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Отслеживание размонтирования функционального компонента

Это фундаментальный вопрос о React lifecycle. В функциональных компонентах размонтирование отслеживается через cleanup функцию в useEffect.

Основной способ: return из useEffect

import { useEffect } from 'react';

export function ChatWindow({ userId }) {
  useEffect(() => {
    console.log('Компонент смонтирован');

    // Cleanup функция вызывается при размонтировании
    return () => {
      console.log('Компонент размонтирован');
      // Здесь очищаем ресурсы
    };
  }, []); // Пустой массив зависимостей = выполнить один раз

  return <div>Чат</div>;
}

Когда компонент удаляется из DOM, React вызывает cleanup функцию (return из useEffect). Это идеальное место для:

  • Отписки от WebSocket
  • Отмены HTTP запросов
  • Удаления event listeners
  • Очистки таймеров
  • Освобождения памяти

Практический пример: WebSocket подписка

function LiveNotifications({ userId }) {
  useEffect(() => {
    const ws = new WebSocket(`wss://api.example.com/notifications/${userId}`);

    ws.onmessage = (event) => {
      console.log('Новое уведомление:', event.data);
    };

    ws.onerror = (error) => {
      console.error('WebSocket ошибка:', error);
    };

    // Cleanup: закрыть соединение при размонтировании
    return () => {
      console.log('Закрываем WebSocket');
      ws.close();
    };
  }, [userId]);

  return <div>Слушаю уведомления...</div>;
}

Отмена HTTP запросов

function UserProfile({ userId }) {
  const [user, setUser] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    const abortController = new AbortController();

    const fetchUser = async () => {
      try {
        const response = await fetch(`/api/users/${userId}`, {
          signal: abortController.signal
        });
        const data = await response.json();
        setUser(data);
      } catch (error) {
        if (error.name !== 'AbortError') {
          console.error('Ошибка загрузки:', error);
        }
      } finally {
        setLoading(false);
      }
    };

    fetchUser();

    // Cleanup: отменить запрос если компонент размонтирован
    return () => {
      abortController.abort();
    };
  }, [userId]);

  if (loading) return <div>Загрузка...</div>;
  return <div>{user?.name}</div>;
}

Очистка таймеров и интервалов

function Timer() {
  const [seconds, setSeconds] = useState(0);

  useEffect(() => {
    const interval = setInterval(() => {
      setSeconds(s => s + 1);
    }, 1000);

    // Cleanup: остановить интервал
    return () => {
      console.log('Очищаем интервал');
      clearInterval(interval);
    };
  }, []);

  return <div>{seconds} сек</div>;
}

Специальный хук для размонтирования

Можно создать кастомный хук для упрощения:

function useOnUnmount(callback) {
  useEffect(() => {
    return () => callback();
  }, [callback]);
}

// Использование:
function MyComponent() {
  useOnUnmount(() => {
    console.log('Компонент размонтирован!');
  });

  return <div>Контент</div>;
}

Важные моменты

  1. Cleanup запускается:

    • При размонтировании компонента
    • При изменении зависимостей (перед новым effect)
  2. Зависимости имеют значение:

    • [] = выполнить один раз (только при монтировании)
    • [userId] = при каждом изменении userId
    • Без массива = при каждом ре-рендере (обычно не нужно)`
  3. Частая ошибка: забыть очистить ресурсы приводит к утечкам памяти и багам:

    • WebSocket остаётся открытым
    • Таймер продолжает работать
    • Event listener висит в памяти

Это ключевая концепция для создания надёжных React приложений без утечек памяти и неожиданного поведения.