Пользовательские хуки — это функции, создаваемые разработчиком для
переиспользования логики состояния и побочных эффектов в компонентах.
Они расширяют возможности стандартных хуков React, таких как
useState, useEffect, useMemo и
useCallback, предоставляя структурированный и модульный
подход к организации кода. Пользовательские хуки не являются
компонентами и всегда должны следовать правилам хуков: вызывать их
только на верхнем уровне функции и не внутри условных операторов или
циклов.
Пользовательский хук создается как обычная функция, имя которой
начинается с префикса use. Это обязательное правило,
позволяющее React корректно отслеживать вызовы хуков:
import { useState, useEffect } from 'react';
function useFetch(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
setLoading(true);
fetch(url)
.then(response => response.json())
.then(json => setData(json))
.catch(err => setError(err))
.finally(() => setLoading(false));
}, [url]);
return { data, loading, error };
}
В этом примере useFetch инкапсулирует логику получения
данных с сервера. Любой компонент может использовать этот хук для
получения данных без дублирования кода.
Инкапсуляция состояния и побочных эффектов Хук должен скрывать внутреннюю реализацию состояния и побочных эффектов. Компонент получает только нужные значения и функции управления.
Возврат объектов или массивов Пользовательские хуки обычно возвращают объект или массив, содержащий состояние и функции. Объект удобен для именованных значений, массив — для последовательного деструктурирования.
const { data, loading, error } = useFetch('https://api.example.com/items');
Повторное использование логики Любая логика, которая повторяется в нескольких компонентах, может быть вынесена в хук. Это улучшает читаемость и поддержку кода.
Следование правилам хуков Пользовательские хуки обязаны вызывать другие хуки только на верхнем уровне функции. Любое условное использование нарушает работу внутреннего механизма React и вызывает ошибки.
Хук для формы с валидацией
import { useState } from 'react';
function useForm(initialValues, validate) {
const [values, setValues] = useState(initialValues);
const [errors, setErrors] = useState({});
const handleChange = (event) => {
const { name, value } = event.target;
setValues(prev => ({ ...prev, [name]: value }));
};
const handleSubmit = (callback) => (event) => {
event.preventDefault();
const validationErrors = validate(values);
setErrors(validationErrors);
if (Object.keys(validationErrors).length === 0) {
callback();
}
};
return { values, errors, handleChange, handleSubmit };
}
Такой хук позволяет обрабатывать любые формы с минимальными усилиями, обеспечивая централизованную валидацию.
Хук для локального хранения состояния
import { useState, useEffect } from 'react';
function useLocalStorage(key, 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;
}
});
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];
}
useLocalStorage синхронизирует состояние компонента с
localStorage, что удобно для сохранения настроек или данных
между сессиями.
Пользовательские хуки можно комбинировать для создания сложных функциональных блоков:
function useAuthenticatedFetch(url, token) {
const { data, loading, error } = useFetch(url);
const [authError, setAuthError] = useState(null);
useEffect(() => {
if (error && error.status === 401) {
setAuthError('Необходима аутентификация');
}
}, [error]);
return { data, loading, error: authError || error };
}
Комбинация нескольких хуков позволяет строить иерархии логики, сохраняя чистоту компонентов и избегая дублирования кода.
use в названии каждого хука.useEffect, чтобы избежать
бесконечных циклов рендеринга.Пользовательские хуки повышают модульность, читаемость и повторное использование кода, становясь ключевым инструментом при построении сложных интерфейсов на React.