Русский

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

Пользовательские хуки: шаблоны повторно используемой логики в React

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

Что такое пользовательские хуки?

По сути, пользовательский хук — это функция JavaScript, название которой начинается со слова «use» и которая может вызывать другие хуки. Они позволяют извлекать логику компонента в повторно используемые функции. Это мощный способ совместного использования логики с состоянием, побочных эффектов или другого сложного поведения между компонентами, не прибегая к рендер-пропсам, компонентам высшего порядка или другим сложным паттернам.

Ключевые характеристики пользовательских хуков:

Преимущества использования пользовательских хуков

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

Создание вашего первого пользовательского хука

Давайте проиллюстрируем создание пользовательского хука на практическом примере: хук, который отслеживает размер окна.

Пример: useWindowSize

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

import { useState, useEffect } from 'react';

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

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

    window.addEventListener('resize', handleResize);

    // Удаляем обработчик события при очистке
    return () => window.removeEventListener('resize', handleResize);
  }, []); // Пустой массив зависимостей гарантирует, что эффект запустится только при монтировании

  return windowSize;
}

export default useWindowSize;

Объяснение:

  1. Импорт необходимых хуков: Мы импортируем useState и useEffect из React.
  2. Определение хука: Мы создаем функцию с именем useWindowSize, соблюдая соглашение об именовании.
  3. Инициализация состояния: Мы используем useState для инициализации состояния windowSize начальной шириной и высотой окна.
  4. Настройка обработчика событий: Мы используем useEffect для добавления обработчика события изменения размера окна. Когда размер окна изменяется, функция handleResize обновляет состояние windowSize.
  5. Очистка: Мы возвращаем функцию очистки из useEffect для удаления обработчика событий при размонтировании компонента. Это предотвращает утечки памяти.
  6. Возврат значений: Хук возвращает объект windowSize, содержащий текущую ширину и высоту окна.

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

Теперь, когда мы создали наш пользовательский хук, давайте посмотрим, как использовать его в компоненте React.

import React from 'react';
import useWindowSize from './useWindowSize';

function MyComponent() {
  const { width, height } = useWindowSize();

  return (
    

Ширина окна: {width}px

Высота окна: {height}px

); } export default MyComponent;

Объяснение:

  1. Импорт хука: Мы импортируем пользовательский хук useWindowSize.
  2. Вызов хука: Мы вызываем хук useWindowSize внутри компонента.
  3. Доступ к значениям: Мы деструктурируем возвращаемый объект, чтобы получить значения width и height.
  4. Отрисовка значений: Мы отображаем значения ширины и высоты в пользовательском интерфейсе компонента.

Любой компонент, использующий useWindowSize, будет автоматически обновляться при изменении размера окна.

Более сложные примеры

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

Пример: useLocalStorage

Этот хук позволяет легко сохранять и извлекать данные из локального хранилища (local storage).

import { useState, useEffect } from 'react';

function useLocalStorage(key, initialValue) {
  // Состояние для хранения нашего значения
  // Передаем начальное значение в useState, чтобы логика выполнилась только один раз
  const [storedValue, setStoredValue] = useState(() => {
    try {
      // Получаем из локального хранилища по ключу
      const item = window.localStorage.getItem(key);
      // Парсим сохраненный json или, если его нет, возвращаем начальное значение
      return item ? JSON.parse(item) : initialValue;
    } catch (error) {
      // В случае ошибки также возвращаем начальное значение
      console.log(error);
      return initialValue;
    }
  });

  // Возвращаем обернутую версию сеттера из useState, которая...
  // ... сохраняет новое значение в localStorage.
  const setValue = (value) => {
    try {
      // Разрешаем значению быть функцией, чтобы иметь тот же API, что и у useState
      const valueToStore = value instanceof Function ? value(storedValue) : value;
      // Сохраняем в локальное хранилище
      window.localStorage.setItem(key, JSON.stringify(valueToStore));
      // Сохраняем состояние
      setStoredValue(valueToStore);
    } catch (error) {
      // Более продвинутая реализация обработала бы случай ошибки
      console.log(error);
    }
  };

  useEffect(() => {
    try {
      const item = window.localStorage.getItem(key);
      setStoredValue(item ? JSON.parse(item) : initialValue);
    } catch (error) {
      console.log(error);
    }
  }, [key, initialValue]);

  return [storedValue, setValue];
}

export default useLocalStorage;

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

import React from 'react';
import useLocalStorage from './useLocalStorage';

function MyComponent() {
  const [name, setName] = useLocalStorage('name', 'Гость');

  return (
    

Привет, {name}!

setName(e.target.value)} />
); } export default MyComponent;

Пример: useFetch

Этот хук инкапсулирует логику для получения данных из API.

import { useState, useEffect } from 'react';

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

  useEffect(() => {
    async function fetchData() {
      try {
        const response = await fetch(url);
        if (!response.ok) {
          throw new Error(`HTTP ошибка! статус: ${response.status}`);
        }
        const json = await response.json();
        setData(json);
        setLoading(false);
      } catch (error) {
        setError(error);
        setLoading(false);
      }
    }

    fetchData();
  }, [url]);

  return { data, loading, error };
}

export default useFetch;

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

import React from 'react';
import useFetch from './useFetch';

function MyComponent() {
  const { data, loading, error } = useFetch('https://jsonplaceholder.typicode.com/todos/1');

  if (loading) return 

Загрузка...

; if (error) return

Ошибка: {error.message}

; return (

Заголовок: {data.title}

Завершено: {data.completed ? 'Да' : 'Нет'}

); } export default MyComponent;

Лучшие практики для пользовательских хуков

Чтобы ваши пользовательские хуки были эффективными и поддерживаемыми, следуйте этим лучшим практикам:

Частые ошибки, которых следует избегать

Продвинутые паттерны

Композиция пользовательских хуков

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

Совместное использование логики между хуками

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

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

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

Примеры из реального мира

Вот несколько примеров того, как пользовательские хуки могут быть использованы в реальных приложениях:

Пример: хук useGeolocation для кросс-культурных приложений, таких как картографические сервисы или службы доставки

import { useState, useEffect } from 'react';

function useGeolocation() {
  const [location, setLocation] = useState({
    latitude: null,
    longitude: null,
    error: null,
  });

  useEffect(() => {
    if (!navigator.geolocation) {
      setLocation({
        latitude: null,
        longitude: null,
        error: 'Геолокация не поддерживается этим браузером.',
      });
      return;
    }

    const watchId = navigator.geolocation.watchPosition(
      (position) => {
        setLocation({
          latitude: position.coords.latitude,
          longitude: position.coords.longitude,
          error: null,
        });
      },
      (error) => {
        setLocation({
          latitude: null,
          longitude: null,
          error: error.message,
        });
      }
    );

    return () => navigator.geolocation.clearWatch(watchId);
  }, []);

  return location;
}

export default useGeolocation;

Заключение

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

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

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