Українська

Розкрийте силу логіки для повторного використання у 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, щоб додати до вікна слухач події resize. Коли розмір вікна змінюється, функція 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. Рендеринг значень: Ми рендеримо значення ширини та висоти в UI компонента.

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

Більш складні приклади

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

Приклад: useLocalStorage

Цей хук дозволяє легко зберігати та отримувати дані з локального сховища.

import { useState, useEffect } from 'react';

function useLocalStorage(key, initialValue) {
  // Стан для зберігання нашого значення
  // Передаємо початкове значення в useState, щоб логіка виконувалася лише один раз
  const [storedValue, setStoredValue] = useState(() => {
    try {
      // Отримуємо з локального сховища за ключем
      const item = window.localStorage.getItem(key);
      // Парсимо збережений json або повертаємо initialValue, якщо його немає
      return item ? JSON.parse(item) : initialValue;
    } catch (error) {
      // У разі помилки також повертаємо initialValue
      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', 'Guest');

  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 для автоматичного збереження завантажених даних у локальне сховище.

Обмін логікою між хуками

Якщо кілька кастомних хуків мають спільну логіку, ви можете винести цю логіку в окрему утилітарну функцію та повторно використовувати її в обох хуках.

Використання Context з кастомними хуками

Кастомні хуки можна використовувати разом із 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.

Кастомні хуки: Патерни повторно використовуваної логіки в React | MLOG