Отключение от DOM

В Atomico управление жизненным циклом компонентов строится вокруг явного и аккуратного подключения и отключения элементов от DOM. Понимание механизма отключения от DOM необходимо для предотвращения утечек памяти, правильного завершения асинхронных операций и корректной очистки ресурсов.

Жизненный цикл компонента

Каждый компонент в Atomico проходит через несколько этапов:

  1. Создание экземпляра — вызов функции component.
  2. Монтирование в DOM — вставка элемента в дерево документа.
  3. Обновления состояния — реактивные изменения через useState или useReducer.
  4. Отключение от DOM — момент, когда элемент удаляется из документа.

Для отключения существует специальный механизм, основанный на функции onUnmount. Она регистрирует коллбеки, которые будут вызваны при удалении компонента из DOM.

Функция onUnmount

Функция onUnmount используется внутри тела компонента. Ее синтаксис:

import { component, useState, onUnmount } from "atomico";

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

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

    onUnmount(() => {
        clearInterval(interval);
        console.log("Компонент удалён, таймер остановлен");
    });

    return <host>{seconds}</host>;
}

export default component(Timer);

Ключевые моменты:

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

Использование с подписками на события

Когда компонент регистрирует обработчики событий, важно их удалять при отключении. Пример с событием click:

function ClickCounter() {
    const [count, setCount] = useState(0);

    const handleClick = () => setCount(c => c + 1);

    document.addEventListener("click", handleClick);

    onUnmount(() => {
        document.removeEventListener("click", handleClick);
    });

    return <host>Кликов: {count}</host>;
}

export default component(ClickCounter);

Без onUnmount обработчик останется активным даже после удаления компонента, что приведёт к утечке памяти и некорректным обновлениям.

Очистка асинхронных операций

Асинхронные операции, такие как fetch или таймеры, могут продолжать работать после удаления компонента. onUnmount позволяет остановить их безопасно:

function DataLoader() {
    const [data, setData] = useState(null);
    let controller = new AbortController();

    fetch("/api/data", { signal: controller.signal })
        .then(res => res.json())
        .then(setData);

    onUnmount(() => {
        controller.abort();
        console.log("Асинхронная операция отменена");
    });

    return <host>{data ? JSON.stringify(data) : "Загрузка..."}</host>;
}

export default component(DataLoader);

Взаимодействие с дочерними компонентами

Если компонент содержит дочерние компоненты, onUnmount вызывается рекурсивно для каждого элемента дерева. Это означает, что очистка ресурсов может быть распределена между несколькими уровнями, и нет необходимости вручную обрабатывать дочерние компоненты. Однако рекомендуется проверять асинхронные операции на верхнем уровне, чтобы избежать лишнего выполнения после удаления.

Отложенная очистка и эффекты

Atomico предоставляет удобный способ комбинировать эффекты с onUnmount через useEffect:

import { useEffect } from "atomico";

function EffectExample() {
    useEffect(() => {
        const id = setInterval(() => console.log("tick"), 1000);

        return () => clearInterval(id); // автоматически вызывается через onUnmount
    }, []);

    return <host>Эффект активен</host>;
}

export default component(EffectExample);

В этом примере функция очистки внутри useEffect эквивалентна регистрации через onUnmount.

Практические рекомендации

  • Всегда регистрировать очистку сторонних ресурсов через onUnmount.
  • Для таймеров, интервалов и подписок на события использовать явное удаление.
  • Для асинхронных операций применять AbortController или аналогичные механизмы отмены.
  • Проверять, что дочерние компоненты корректно завершают свои эффекты.

Правильное использование механизма отключения от DOM обеспечивает устойчивость приложения, предотвращает утечки памяти и упрощает управление состоянием компонентов в больших проектах.