useEffect для побочных эффектов

useEffect в Preact является одним из основных хуков для работы с побочными эффектами в функциональных компонентах. Его основная цель — выполнять код после того, как компонент отрендерился, а также управлять жизненным циклом этого кода при изменении зависимостей.

Синтаксис

import { h } from 'preact';
import { useEffect } from 'preact/hooks';

useEffect(() => {
    // код побочного эффекта
    return () => {
        // код очистки эффекта (опционально)
    };
}, [dependencies]);
  • callback — функция, которая выполняется после рендера компонента.
  • dependencies — массив зависимостей, от изменения которых зависит повторное выполнение эффекта.
  • return — функция очистки эффекта, вызываемая перед повторным выполнением эффекта и при размонтировании компонента.

Виды использования

  1. Эффект без зависимостей Если массив зависимостей пустой, эффект выполняется только один раз после первого рендера, аналогично componentDidMount:
useEffect(() => {
    console.log('Компонент смонтирован');
}, []);
  1. Эффект с зависимостями Эффект выполняется каждый раз, когда меняется хотя бы одна из указанных зависимостей:
const [count, setCount] = useState(0);

useEffect(() => {
    console.log(`Значение count изменилось: ${count}`);
}, [count]);
  1. Эффект без массива зависимостей Если массив зависимостей не указан, эффект будет выполняться после каждого рендера компонента:
useEffect(() => {
    console.log('Компонент обновился');
});

Функция очистки эффекта

Возвращаемая из useEffect функция используется для освобождения ресурсов, отписки от событий, отмены таймеров или запросов:

useEffect(() => {
    const intervalId = setInterval(() => {
        console.log('Таймер сработал');
    }, 1000);

    return () => {
        clearInterval(intervalId);
        console.log('Таймер очищен');
    };
}, []);

Функция очистки вызывается:

  • перед повторным выполнением эффекта (если массив зависимостей не пустой),
  • при размонтировании компонента.

Асинхронные эффекты

useEffect не может принимать асинхронную функцию напрямую. Для выполнения асинхронного кода внутри эффекта создается вложенная функция:

useEffect(() => {
    const fetchData = async () => {
        const response = await fetch('https://api.example.com/data');
        const data = await response.json();
        console.log(data);
    };

    fetchData();
}, []);

Частые ошибки и оптимизация

  • Игнорирование зависимостей Если зависимости указаны неверно или пропущены, эффект может работать некорректно. Важно включать все значения, используемые внутри эффекта, кроме констант и функций, определённых вне компонента.

  • Чрезмерные эффекты Использование эффекта без зависимостей для кода, который не требует постоянного выполнения, приводит к лишним рендерам и нагрузке на производительность.

  • Очистка ресурсов Всегда проверять, что эффекты освобождают ресурсы. Неправильная очистка может вызвать утечки памяти или некорректное поведение при размонтировании.

Практические сценарии использования

  • Подписка на события:
useEffect(() => {
    const handleResize = () => console.log(window.innerWidth);
    window.addEventListener('resize', handleResize);

    return () => {
        window.removeEventListener('resize', handleResize);
    };
}, []);
  • Работа с таймерами:
useEffect(() => {
    const timer = setTimeout(() => console.log('Прошло 3 секунды'), 3000);

    return () => clearTimeout(timer);
}, []);
  • Синхронизация состояния с внешними источниками данных:
useEffect(() => {
    document.title = `Вы нажали ${count} раз`;
}, [count]);

Особенности Preact

В Preact useEffect работает практически идентично React, но с более лёгким и быстрым механизмом рендеринга. Отличие заключается в том, что Preact стремится минимизировать количество вызовов эффекта при множественных обновлениях, особенно если используется preact/compat.

useEffect является базовым инструментом для управления побочными эффектами и синхронизации состояния с внешним миром, обеспечивая точное управление временем выполнения и очисткой ресурсов.