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

Inferno предоставляет мощный механизм для работы с хуками, позволяя управлять состоянием компонентов и их жизненным циклом с высокой производительностью. Хуки — это функции, которые позволяют «подключаться» к состоянию и другим возможностям Inferno без использования классов. Основные встроенные хуки включают useState, useEffect, useRef, useMemo и useCallback.

useState создаёт локальное состояние внутри функционального компонента. Его использование аналогично React, однако Inferno реализует его с минимальной нагрузкой на рендеринг, обеспечивая более быструю реакцию интерфейса.

import { useState } from 'inferno-hooks';

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

    return (
        <button onCl ick={() => setCount(count + 1)}>
            {count}
        </button>
    );
}

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

import { useEffect } from 'inferno-hooks';

function Timer() {
    useEffect(() => {
        const interval = setInterval(() => console.log('tick'), 1000);
        return () => clearInterval(interval);
    }, []);
    
    return <div>Таймер запущен</div>;
}

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

Создание собственного хука начинается с функции, название которой должно начинаться с use. Внутри функции могут использоваться другие хуки, состояние и логика обработки эффектов.

Пример пользовательского хука useWindowWidth:

import { useState, useEffect } from 'inferno-hooks';

function useWindowWidth() {
    const [width, setWidth] = useState(window.innerWidth);

    useEffect(() => {
        const handleResize = () => setWidth(window.innerWidth);
        window.addEventListener('resize', handleResize);
        return () => window.removeEventListener('resize', handleResize);
    }, []);

    return width;
}

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

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

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

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

    useEffect(() => {
        let isMounted = true;
        setLoading(true);

        fetch(url)
            .then(response => response.json())
            .then(json => {
                if (isMounted) {
                    setData(json);
                    setLoading(false);
                }
            });

        return () => { isMounted = false; };
    }, [url]);

    return { data, loading };
}

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

Комбинирование хуков

Собственные хуки можно комбинировать для создания более сложной функциональности. Например, объединение useWindowWidth и useFetch позволяет подгружать данные в зависимости от ширины экрана:

function useResponsiveData(apiUrl) {
    const width = useWindowWidth();
    const { data, loading } = useFetch(`${apiUrl}?width=${width}`);
    
    return { data, loading, width };
}

Использование хуков с контекстом

Inferno поддерживает создание контекста через createContext и его использование в пользовательских хуках. Это позволяет централизованно управлять состоянием приложения.

import { createContext } from 'inferno';
import { useContext, useState } from 'inferno-hooks';

const ThemeContext = createContext('light');

function useTheme() {
    return useContext(ThemeContext);
}

function ThemeProvider({ children }) {
    const [theme, setTheme] = useState('light');

    return (
        <ThemeContext.Provider value={{ theme, setTheme }}>
            {children}
        </ThemeContext.Provider>
    );
}

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

Пользовательские хуки могут включать мемоизацию значений через useMemo и функций через useCallback для уменьшения количества лишних рендеров и пересозданий функций.

import { useMemo, useCallback } from 'inferno-hooks';

function useSortedData(data) {
    const sorted = useMemo(() => data.slice().sort(), [data]);
    
    const getItem = useCallback(index => sorted[index], [sorted]);
    
    return { sorted, getItem };
}

Рекомендации по построению пользовательских хуков

  • Названия должны начинаться с use.
  • Не вызывать хуки условно или внутри циклов.
  • Инкапсулировать повторяющийся код для переиспользования.
  • Управлять эффектами аккуратно, правильно указывая зависимости.
  • Применять мемоизацию для оптимизации вычислений и функций.

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