Как использовать useEffect?react-20

useEffect — это хук (hook) для работы с побочными эффектами (side effects) в функциональных компонентах React. Он объединяет функциональность методов жизненного цикла классовых компонентов: componentDidMount, componentDidUpdate и componentWillUnmount.

Базовый синтаксис

import { useEffect } from 'react';

useEffect(() => {
  // Код эффекта (effect logic)
  return () => {
    // Функция очистки (cleanup function)
  };
}, [dependencies]); // Массив зависимостей

Основные сценарии использования

1. Запуск эффекта один раз

useEffect(() => {
  console.log('Компонент смонтирован');
  fetchData(); // Загрузка данных при монтировании

  return () => {
    console.log('Компонент будет размонтирован');
  };
}, []); // Пустой массив зависимостей

2. Запуск эффекта при изменении зависимостей

useEffect(() => {
  document.title = `Новое сообщение: ${message}`;
}, [message]); // Зависимость от message

3. Эффект с очисткой

useEffect(() => {
  const timer = setInterval(() => {
    console.log('Тик');
  }, 1000);

  return () => {
    clearInterval(timer); // Очистка при размонтировании
  };
}, []);

Практические примеры

Работа с API

useEffect(() => {
  let isMounted = true;
  const controller = new AbortController();

  async function fetchData() {
    try {
      const response = await fetch('/api/data', {
        signal: controller.signal
      });
      if (isMounted) {
        setData(await response.json());
      }
    } catch (error) {
      if (error.name !== 'AbortError') {
        console.error('Ошибка загрузки:', error);
      }
    }
  }

  fetchData();

  return () => {
    isMounted = false;
    controller.abort(); // Отмена запроса при размонтировании
  };
}, [query]); // Зависит от параметра query

Подписка на события

useEffect(() => {
  function handleResize() {
    setWindowSize({
      width: window.innerWidth,
      height: window.innerHeight
    });
  }

  window.addEventListener('resize', handleResize);

  return () => {
    window.removeEventListener('resize', handleResize);
  };
}, []); // Нет зависимостей - подписка только при монтировании

Важные особенности

  1. Массив зависимостей:

    • [] — эффект выполняется один раз (при монтировании)
    • [dep1, dep2] — эффект при изменении dep1 или dep2
    • Нет массива — эффект при каждом рендере
  2. Порядок выполнения:

    • Эффекты выполняются после рендеринга
    • Очистка предыдущего эффекта выполняется перед следующим
  3. Несколько эффектов:

    // Можно разделять логику на несколько useEffect
    useEffect(() => { /* логика 1 */ }, [dep1]);
    useEffect(() => { /* логика 2 */ }, [dep2]);
    

Распространенные ошибки

  1. Забывают про очистку:

    // Плохо: утечка памяти
    useEffect(() => {
      setInterval(() => {}, 1000);
    }, []);
    
    // Хорошо:
    useEffect(() => {
      const id = setInterval(() => {}, 1000);
      return () => clearInterval(id);
    }, []);
    
  2. Неправильные зависимости:

    // Пропущена зависимость
    useEffect(() => {
      fetchUser(userId);
    }, []); // Должно быть [userId]
    
  3. Бесконечные циклы:

    // Бесконечный рендеринг
    useEffect(() => {
      setCount(count + 1);
    }, [count]); // Эффект изменяет свою зависимость
    

Оптимизация производительности

  1. Мемоизация колбэков:

    const fetchData = useCallback(() => {
      // логика запроса
    }, [query]);
    
    useEffect(() => {
      fetchData();
    }, [fetchData]);
    
  2. Разделение эффектов:

    // Разделение несвязанной логики
    useEffect(() => { /* логика A */ }, [depA]);
    useEffect(() => { /* логика B */ }, [depB]);
    

Резюмируем

useEffect — это мощный инструмент для работы с побочными эффектами в функциональных компонентах React. Он заменяет методы жизненного цикла классовых компонентов, предлагая более гибкий и понятный способ управления side effects. Правильное использование useEffect требует понимания его работы с зависимостями, важности очистки эффектов и особенностей выполнения. Этот хук является фундаментальным для современных React-приложений и его грамотное применение критически важно для создания надежных и эффективных компонентов.