Пользовательские Hooks

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

Зачем нужны

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

Преимущества:

  • Логика изолирована и тестируема
  • Компоненты становятся чище и короче
  • Поведение легко переиспользовать

Пример: useLocalStorage

Этот хук инкапсулирует работу с localStorage и синхронизирует её с состоянием компонента:

import { useState, useEffect } from 'react';

function useLocalStorage<T>(key: string, initialValue: T): [T, (value: T) => void] {
  const [storedValue, setStoredValue] = useState<T>(() => {
    try {
      const item = window.localStorage.getItem(key);
      return item ? JSON.parse(item) : initialValue;
    } catch (error) {
      console.error(`Ошибка при чтении ${key} из localStorage:`, error);
      return initialValue;
    }
  });

  const setValue = (value: T) => {
    try {
      setStoredValue(value);
      window.localStorage.setItem(key, JSON.stringify(value));
    } catch (error) {
      console.error(`Ошибка при записи ${key} в localStorage:`, error);
    }
  };

  return [storedValue, setValue];
}

Использование:

function App() {
  const [name, setName] = useLocalStorage('userName', 'Гость');
  return <input value={name} onChange={(e) => setName(e.target.value)} />;
}

Пример: useWindowSize

Хук для отслеживания размеров окна браузера:

import { useState, useEffect } from 'react';

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

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

    window.addEventListener('resize', handleResize);
    return () => window.removeEventListener('resize', handleResize);
  }, []);

  return windowSize;
}

Использование:

function ResponsiveComponent() {
  const { width } = useWindowSize();
  return <div>Ширина окна: {width}px</div>;
}

Правила создания

  • Имя всегда начинается с use
  • Может вызывать другие хуки (useState, useEffect, useContext и т.д.)
  • Не принимает JSX и не возвращает JSX — только данные и функции управления ими
  • Должен быть чистым по отношению к компоненту: не зависит от конкретного UI

Когда не стоит создавать хук

  • Если логика используется только в одном месте
  • Если она слишком специфична и не поддаётся обобщению
  • Если проще передать колбэк или использовать пропсы

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