Создание собственных хуков

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


Основы пользовательских хуков

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

Пример базового хука для управления счетчиком:

import { useState } FROM "atomico";

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

    const increment = () => setCount(count + 1);
    const decrement = () => setCount(count - 1);
    const reset = () => setCount(initial);

    return { count, increment, decrement, reset };
}

Этот хук возвращает объект с текущим значением счетчика и функциями для изменения состояния. Такой подход упрощает повторное использование логики в разных компонентах.


Передача параметров и конфигурация хуков

Хуки могут принимать аргументы для настройки поведения. Это позволяет создавать универсальные и настраиваемые функции.

Пример хука с параметрами для таймера:

import { useState, useEffect } FROM "atomico";

function useTimer(duration = 1000) {
    const [time, setTime] = useState(0);

    useEffect(() => {
        const interval = setInterval(() => {
            setTime(prev => prev + 1);
        }, duration);

        return () => clearInterval(interval);
    }, [duration]);

    return time;
}

Здесь duration задает интервал обновления, и использование зависимости в useEffect обеспечивает корректную работу при изменении параметра.


Композиция хуков

Хуки в Atomico можно комбинировать, создавая более сложные логические блоки. Это позволяет строить иерархии хуков, где один хук использует другой для расширения функционала.

Пример композиции:

function useCounterWithLimit(initial, LIMIT) {
    const counter = useCounter(initial);

    const increment = () => {
        if (counter.count < LIMIT) counter.increment();
    };

    return { ...counter, increment };
}

Таким образом, базовый хук useCounter расширяется функционалом ограничения максимального значения.


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

Хуки идеально подходят для управления асинхронными операциями, такими как запросы к API. Для этого часто используют комбинацию useState и useEffect.

Пример пользовательского хука для получения данных:

import { useState, useEffect } from "atomico";

function useFetch(url) {
    const [data, setData] = useState(null);
    const [loading, setLoading] = useState(true);
    const [error, setError] = useState(null);

    useEffect(() => {
        setLoading(true);
        fetch(url)
            .then(res => res.json())
            .then(setData)
            .catch(setError)
            .finally(() => setLoading(false));
    }, [url]);

    return { data, loading, error };
}

Хук useFetch инкапсулирует логику загрузки данных, обработки ошибок и управления состоянием загрузки, делая компоненты чистыми и минимальными.


Хуки с мемоизацией и оптимизацией

Atomico поддерживает мемоизацию значений и функций через useMemo и useCallback. Это полезно для оптимизации производительности, особенно когда вычисления ресурсоемкие или функции передаются глубоко вниз по дереву компонентов.

Пример мемоизированного значения:

import { useMemo } from "atomico";

function useFilteredList(list, filter) {
    return useMemo(() => list.filter(item => item.includes(filter)), [list, filter]);
}

Создание хуков с побочными эффектами

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

Пример хука, реагирующего на изменение размера окна:

import { useState, useEffect } from "atomico";

function useWindowSize() {
    const [size, setSize] = useState({ width: window.innerWidth, height: window.innerHeight });

    useEffect(() => {
        const onRes ize = () => setSize({ width: window.innerWidth, height: window.innerHeight });
        window.addEventListener("resize", onResize);
        return () => window.removeEventListener("resize", onResize);
    }, []);

    return size;
}

Инкапсуляция сложной логики

Пользовательские хуки позволяют скрыть сложные детали реализации и предоставить простой интерфейс для компонентов. Любую повторяющуюся или комплексную логику можно вынести в хук.

Пример:

function useAuth() {
    const [user, setUser] = useState(null);

    const login = async (credentials) => {
        const response = await fetch("/login", { method: "POST", body: JSON.stringify(credentials) });
        const data = await response.json();
        setUser(data.user);
    };

    const logout = () => setUser(null);

    return { user, login, logout };
}

Советы по проектированию хуков

  • Прозрачность интерфейса: хук должен возвращать минимально необходимый набор данных и функций.
  • Изоляция состояния: внутреннее состояние хуков не должно напрямую зависеть от внешних компонентов.
  • Стабильность зависимостей: использовать useMemo и useCallback для предотвращения лишних пересозданий функций и объектов.
  • Чистота побочных эффектов: все побочные эффекты должны корректно очищаться через функции возврата в useEffect.

Хуки в Atomico создают мощный инструмент для модульного проектирования компонентов, позволяя строить легко поддерживаемые и повторно используемые логические блоки без дублирования кода.