Как создать собственный хук?react-22

Собственный хук — это JavaScript-функция, имя которой начинается с "use", и которая может вызывать другие хуки. Кастомные хуки позволяют извлекать логику компонентов в переиспользуемые функции.

Основные правила создания хуков

  1. Именование должно начинаться с use (например, useFetch, useLocalStorage)
  2. Можно вызывать другие хуки внутри кастомного хука
  3. Нельзя вызывать в условиях и циклах (соблюдаются те же правила, что и для встроенных хуков)

Базовый шаблон кастомного хука

import { useState, useEffect } from 'react';

function useCustomHook(initialValue) {
  const [value, setValue] = useState(initialValue);

  useEffect(() => {
    // Побочные эффекты
  }, [value]);

  // Возвращаем значения, которые будут доступны компоненту
  return [value, setValue];
}

Практические примеры

1. Хук для работы с localStorage

function useLocalStorage(key, initialValue) {
  // Получаем значение из localStorage или используем initialValue
  const [storedValue, setStoredValue] = useState(() => {
    try {
      const item = window.localStorage.getItem(key);
      return item ? JSON.parse(item) : initialValue;
    } catch (error) {
      console.error(error);
      return initialValue;
    }
  });

  // Обновляем localStorage при изменении значения
  const setValue = (value) => {
    try {
      const valueToStore = value instanceof Function ? value(storedValue) : value;
      setStoredValue(valueToStore);
      window.localStorage.setItem(key, JSON.stringify(valueToStore));
    } catch (error) {
      console.error(error);
    }
  };

  return [storedValue, setValue];
}

// Использование в компоненте
const [name, setName] = useLocalStorage('username', 'Гость');

2. Хук для получения данных

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

  useEffect(() => {
    const fetchData = async () => {
      try {
        const response = await fetch(url);
        if (!response.ok) {
          throw new Error('Ошибка загрузки данных');
        }
        const result = await response.json();
        setData(result);
      } catch (err) {
        setError(err.message);
      } finally {
        setLoading(false);
      }
    };

    fetchData();
  }, [url]); // Зависимость от URL

  return { data, loading, error };
}

// Использование в компоненте
const { data, loading, error } = useFetch('https://api.example.com/data');

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

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;
}

// Использование в компоненте
const { width, height } = useWindowSize();

Лучшие практики создания кастомных хуков

  1. Изолированная логика — хук должен решать одну конкретную задачу
  2. Гибкий API — возвращайте значения в удобном для использования формате
  3. Обработка ошибок — предусматривайте возможные ошибки
  4. Оптимизация производительности — используйте useCallback и useMemo где необходимо
  5. Документация — добавляйте JSDoc для описания работы хука

Тестирование кастомных хуков

Для тестирования хуков можно использовать библиотеку @testing-library/react-hooks:

import { renderHook } from '@testing-library/react-hooks';
import useCounter from './useCounter';

test('should increment counter', () => {
  const { result } = renderHook(() => useCounter());

  expect(result.current.count).toBe(0);
  act(() => {
    result.current.increment();
  });
  expect(result.current.count).toBe(1);
});

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

  1. Повторяющаяся логика в нескольких компонентах
  2. Сложные эффекты, которые можно вынести отдельно
  3. Интеграция со сторонними библиотеками
  4. Абстракция сложного поведения компонента

Резюмируем

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