Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Пример и разбор кастомного хука в React
Кастомный хук (custom hook) — это функция, использующая стандартные хуки React (useState, useEffect, useContext, etc.) для создания повторно используемой логики с состоянием. Основное правило: имя должно начинаться с use, чтобы React понимал, что это хук, и мог применять свои правила (например, проверку порядка вызовов хуков).
Практический пример: хук useFetch для управления HTTP-запросами
Одна из самых распространенных задач в фронтенд-разработке — загрузка данных из API. Часто приходится управлять состоянием загрузки (loading), данными (data) и ошибками (error). Чтобы избежать дублирования кода в каждом компоненте, мы можем создать хук useFetch.
import { useState, useEffect } from 'react';
/**
* Кастомный хук для выполнения HTTP-запросов.
* @param {string} url - URL для запроса.
* @param {object} options - Опции для fetch (method, headers, body, etc.).
* @returns {object} Объект с состоянием: { data, loading, error }
*/
function useFetch(url, options = {}) {
// Состояния для данных, загрузки и ошибки
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
// Асинхронная функция для выполнения запроса
const fetchData = async () => {
try {
setLoading(true);
setError(null); // Сбрасываем ошибку перед новым запросом
const response = await fetch(url, options);
// Проверяем статус ответа
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const jsonData = await response.json();
setData(jsonData);
} catch (err) {
setError(err.message || 'An unknown error occurred');
setData(null); // Сбрасываем данные при ошибке
} finally {
setLoading(false);
}
};
fetchData();
// Опционально: добавление зависимости для повторного запроса при изменении url
// Если url или options изменятся, эффект выполнится снова
}, [url]); // Добавляем url в зависимости, чтобы запрос повторялся при его изменении
// Возвращаем объект с состояниями, чтобы компонент мог их использовать
return { data, loading, error };
}
export default useFetch;
Использование хука useFetch в компоненте
Теперь любой компонент может использовать этот хук, чтобы получить данные без повторения логики управления состоянием.
import React from 'react';
import useFetch from './useFetch'; // Импорт кастомного хука
function UserProfile({ userId }) {
// Используем хук. При изменении userId запрос автоматически повторяется.
const { data: user, loading, error } = useFetch(`https://api.example.com/users/${userId}`);
// Рендер компонента на основе состояния
if (loading) return <div>Loading user profile...</div>;
if (error) return <div>Error: {error}</div>;
return (
<div>
<h1>User Profile</h1>
<p><strong>Name:</strong> {user.name}</p>
<p><strong>Email:</strong> {user.email}</p>
</div>
);
}
export default UserProfile;
Преимущества кастомного хука useFetch
- Уменьшение дублирования кода: Логика запроса, обработки ошибок и управления состоянием загрузки инкапсулирована в одном месте.
- Упрощение компонентов: Компоненты становятся более чистыми и читаемыми, фокусируются на рендере, а не на побочных эффектах.
- Легкость тестирования: Хук можно тестировать отдельно от компонентов.
- Совместное использование: Любой компонент в приложении может импортировать и использовать
useFetch. - Стандартизация: Все запросы в приложении будут обрабатываться одинаково, что упрощает поддержку и дебаггинг.
Более сложный пример: хук useLocalStorage
Кастомные хуки могут взаимодействовать не только с API, но и с браузерным API, например, localStorage.
import { useState, useEffect } from 'react';
/**
* Хук для синхронизации состояния React с localStorage.
* @param {string} key - Ключ в localStorage.
* @param {any} initialValue - Начальное значение, если в localStorage ничего нет.
* @returns {[any, function]} Аналогично useState: [value, setValue]
*/
function useLocalStorage(key, initialValue) {
// Функция для чтения начального значения из localStorage или использования initialValue
const readValue = () => {
try {
const item = window.localStorage.getItem(key);
return item ? JSON.parse(item) : initialValue;
} catch (error) {
console.warn(`Error reading localStorage key "${key}":`, error);
return initialValue;
}
};
const [storedValue, setStoredValue] = useState(readValue);
// Функция-обертка для setStoredValue, которая также сохраняет значение в localStorage
const setValue = (value) => {
try {
// Позволяем value быть функцией, как в стандартном useState
const newValue = value instanceof Function ? value(storedValue) : value;
setStoredValue(newValue);
window.localStorage.setItem(key, JSON.stringify(newValue));
} catch (error) {
console.warn(`Error setting localStorage key "${key}":`, error);
}
};
// Слушаем изменения этого ключа в localStorage из других окон (табов)
useEffect(() => {
const handleStorageChange = (e) => {
if (e.key === key && e.newValue !== null) {
setStoredValue(JSON.parse(e.newYearValue));
}
};
window.addEventListener('storage', handleStorageChange);
return () => window.removeEventListener('storage', handleStorageChange);
}, [key]);
return [storedValue, setValue];
}
Использование:
const [theme, setTheme] = useLocalStorage('app-theme', 'light');
// theme автоматически сохраняется в localStorage и восстанавливается при новой загрузке страницы.
Правила создания кастомных хуков
- Начинать с
use: Это соглашение, которое позволяет React (и линтерам) идентифицировать функцию как хук. - Использовать только стандартные хуки внутри: Кастомный хук может вызывать другие кастомные хуки или стандартные хуки React.
- Сохранять чистоту: Хук не должен иметь побочных эффектов на рендер (за исключением тех, что правильно оформлены в
useEffect). - Инкапсулировать логику, а не рендер: Хук возвращает данные или функции, но не JSX. Рендер остается ответственностью компонента.
Кастомные хуки — это мощный инструмент для организации логики в React-приложениях, позволяющий создавать переиспользуемые, тестируемые и поддерживаемые части кода, что соответствует принципам чистого кода и эффективной разработки.