Создание пользовательских хуков для работы с состоянием
Если вы когда-нибудь писали код на React, то, скорее всего, использовали такие встроенные хуки, как useState и useEffect. Хуки позволяют нам подключать функциональность работы с состоянием и побочными эффектами к функциональным компонентам, что делает их очень гибкими и удобными. Однако иногда возникает необходимость использовать одно и то же состояние или логику в нескольких компонентах, и в этом случае на помощь приходят пользовательские хуки.
Пользовательский хук — это просто JavaScript-функция, которая использует встроенные хуки и упрощает повторное использование логики. Давайте разберем, как их создавать.
Что такое хуки в React?
Прежде чем приступить к созданию пользовательских хуков, давайте убедимся, что у нас есть четкое понимание того, что такое хуки и как они работают.
Основные хуки:
- useState: Позволяет компонентам сохранять состояние.
- useEffect: Выполняет побочные эффекты в компонентах (например, подписка на события, запросы на сервер).
- useContext: Подключает контекст (например, глобальное состояние приложения).
Эти хуки часто используются для управления состоянием на уровне компонента. Но что делать, если вам нужно использовать один и тот же набор данных в нескольких местах? Решением может стать создание собственного хука.
Как создавать пользовательские хуки
Пользовательский хук — это функция, которая следует правилам хуков (например, она должна начинаться с "use") и может использовать другие хуки внутри себя.
Давайте создадим простой пользовательский хук, который управляет состоянием счетчика.
Пример 1: Создание простого пользовательского хука useCounter
import { useState } from "react";
function useCounter(initialValue = 0) {
const [count, setCount] = useState(initialValue);
const increment = () => setCount(count + 1);
const decrement = () => setCount(count - 1);
const reset = () => setCount(0);
return { count, increment, decrement, reset };
}
export default useCounter;
Что здесь происходит?
- Мы создали функцию useCounter, которая использует хук useState для управления состоянием счетчика.
- Хук возвращает объект с текущим значением счетчика (count) и функциями для увеличения, уменьшения и сброса значения.
- Теперь этот хук можно использовать в любом компоненте.
Использование хука useCounter:
import React from "react";
import useCounter from "./useCounter";
function CounterComponent() {
const { count, increment, decrement, reset } = useCounter(10);
return (
<div>
<p>Счёт: {count}</p>
<button onClick={increment}>Увеличить</button>
<button onClick={decrement}>Уменьшить</button>
<button onClick={reset}>Сбросить</button>
</div>
);
}
export default CounterComponent;
Здесь мы импортируем наш пользовательский хук useCounter и используем его для управления состоянием счетчика в компоненте. Все просто и понятно!
Когда следует использовать пользовательские хуки?
Теперь, когда мы разобрались, как создавать хуки, возникает вопрос: когда их использовать? Основная причина — это повторное использование логики. Если вы обнаруживаете, что один и тот же код используется в нескольких компонентах, вместо копирования логики, вы можете вынести ее в отдельный пользовательский хук.
Пример 2: Хук для запроса данных — useFetch
Очень часто встречающийся пример — это выполнение HTTP-запросов. Вместо того чтобы каждый раз писать один и тот же код для запроса данных, можно создать хук, который будет повторно использоваться.
import { useState, useEffect } from "react";
function useFetch(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const fetchData = async () => {
setLoading(true);
try {
const response = await fetch(url);
const result = await response.json();
setData(result);
} catch (error) {
setError(error);
}
setLoading(false);
};
fetchData();
}, [url]);
return { data, loading, error };
}
export default useFetch;
Что здесь происходит?
- Хук useFetch принимает URL-адрес для запроса данных.
- Используем useState для хранения состояния данных, загрузки и ошибки.
- useEffect выполняет запрос, когда компонент монтируется или изменяется URL.
- Возвращаем объект с данными, статусом загрузки и ошибкой.
Использование хука useFetch:
import React from "react";
import useFetch from "./useFetch";
function DataComponent() {
const { data, loading, error } = useFetch("https://api.example.com/data");
if (loading) return <p>Загрузка...</p>;
if (error) return <p>Ошибка: {error.message}</p>;
return (
<div>
<h1>Данные:</h1>
<pre>{JSON.stringify(data, null, 2)}</pre>
</div>
);
}
export default DataComponent;
Теперь этот хук можно использовать в любом компоненте, который нуждается в выполнении запроса. Такой подход значительно упрощает код и делает его более читаемым и поддерживаемым.
Продвинутые пользовательские хуки: Комбинирование логики
Иногда вам нужно объединить несколько хуков или логик в один. Пользовательские хуки могут использовать другие хуки внутри себя, что делает их чрезвычайно гибкими.
Пример 3: Хук для отслеживания размеров окна — 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;
}
export default useWindowSize;
Что здесь происходит?
- Мы используем хук useState для хранения текущих размеров окна.
- Хук useEffect добавляет обработчик события resize, который обновляет состояние, когда окно изменяется.
- Возвращаем текущее состояние размеров окна.
Использование хука useWindowSize:
import React from "react";
import useWindowSize from "./useWindowSize";
function WindowSizeComponent() {
const { width, height } = useWindowSize();
return (
<div>
<p>Ширина окна: {width}px</p>
<p>Высота окна: {height}px</p>
</div>
);
}
export default WindowSizeComponent;
Этот хук можно использовать в любом компоненте, где нужно знать размеры окна. Важно, что мы сделали код повторно используемым и легко поддерживаемым.






Комментарии