Кастомный React‑хук useFetch — как и зачем

Зачем выносить логику загрузки в кастомный хук
Кратко: вынос логики загрузки в хук делает код компонентов чище, повышает переиспользуемость и упрощает тестирование. Хук инкапсулирует состояния загрузки, ошибки и данные, а компонент просто их отображает.
Определение терминов (одно предложение):
- useEffect — хук для побочных эффектов, запускается при изменении зависимостей.
- useState — хук для локального состояния в компоненте.
- AbortController — стандартный API для отмены fetch‑запросов.
Принципы хорошего useFetch
- Обрабатывать сетевые ошибки и ошибки формата ответа.
- Возвращать явные состояния: data, loading, error.
- Отменять предыдущий запрос при размонтировании или при смене URL.
- Не изменять состояние после размонтирования компонента.
- Подумать о кешировании и повторных попытках в другом слое (например, React Query).
Пример улучшённого хука useFetch
Ниже — реалистичный и безопасный вариант хука с поддержкой отмены, проверки статуса ответа и аккуратной работой со state:
import { useEffect, useState } from "react";
const useFetch = (url) => {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(Boolean(url));
const [error, setError] = useState(null);
useEffect(() => {
if (!url) {
setData(null);
setLoading(false);
setError(null);
return;
}
const controller = new AbortController();
const signal = controller.signal;
const fetchData = async () => {
setLoading(true);
setError(null);
try {
const res = await fetch(url, { signal });
if (!res.ok) {
// Простая унификация ошибок по статусу
throw new Error(`HTTP error ${res.status}`);
}
const json = await res.json();
// Пример: формат API может отличаться, здесь мы пытаемся безопасно выбрать поле
const payload = json?.joke ?? json?.data ?? json;
setData(payload);
} catch (err) {
if (err.name === 'AbortError') {
// Запрос отменён — игнорируем
return;
}
setError(err.message || 'Unknown error');
} finally {
setLoading(false);
}
};
fetchData();
// Очистка — отмена запроса при размонтировании или смене URL
return () => controller.abort();
}, [url]);
return { data, loading, error };
};
export default useFetch;Important: этот хук рассчитан на общие случаи. Если ваш API возвращает потоковые ответы, multipart или двоичные данные, потребуется другой подход.
Пример использования хука в компоненте
import React from 'react';
import useFetch from './useFetch';
const Jokes = () => {
const url = 'https://sv443.net/jokeapi/v2/joke/Programming?type=single';
const { data, loading, error } = useFetch(url);
if (loading) return Загрузка...;
return (
{error && Ошибка: {error}}
{data && {data}}
);
};
export default Jokes;Советы по использованию:
- Не забывайте кешировать или мемоизировать URL, если он строится динамически.
- Для повторных попыток и продвинутых стратегий используйте библиотеки вроде React Query.
Когда этот подход не подходит
- Если нужен встроенный кеш, дедупликация запросов и повторные попытки — лучше React Query/SWR.
- Для крупных потоковых загрузок (видео, аудио) fetch + JSON не подойдёт.
- Когда нужен персистентный TSO (transactional state) — тогда нужны серверные решения.
Альтернативные подходы
- axios: проще в синтаксисе, автоматически обрабатывает JSON и статусы; поддерживает отмену через CancelToken/AbortController.
- SWR / React Query: добавляют кеширование, фоновое обновление и утилиты для retry и stale‑while‑revalidate.
- GraphQL клиенты (Apollo, Urql) — если API GraphQL.
Ментальные модели и эвристики
- Хук = функция, инкапсулирующая состояние + побочные эффекты. Держите хук маленьким и однозадачным.
- Передавайте только параметры (URL, опции), не абстрагируйте бизнес‑логику внутрь хука.
- Любая асинхронная операция должна предусматривать отмену и обработку ошибок.
Чеклист для разработчика
- URL стабилен и мемоизирован, если вычисляется.
- Обработаны HTTP‑ошибки (res.ok).
- Использован AbortController для отмены.
- Состояние loading переключается корректно (true → false).
- Не устанавливается state после размонтирования компонента.
- Ошибки приводят к понятным сообщениям для пользователя.
Критерии приёмки
- Хук возвращает { data, loading, error } для всех тестовых URL.
- При размонтировании не происходит утечек памяти и не выбрасываются ошибки о setState на размонтированном компоненте.
- Поведение при недоступном API: loading → false, error содержит текст ошибки.
- При успешном ответе data содержит ожидаемую полезную нагрузку.
Тест‑кейсы (минимум)
- Успешный ответ 200 с JSON → loading: false, error: null, data: корректно распарсено.
- HTTP 4xx/5xx → loading: false, error содержит статус.
- Отмена запроса (размонтирование) → нет ошибок, state не меняется после размонтирования.
- Пустой или некорректный URL → hook корректно возвращает loading: false и data: null.
Глоссарий (1‑строчно)
- fetch — встроенный браузерный API для HTTP‑запросов.
- AbortController — механизм отмены fetch‑запроса.
- useEffect/useState — React‑хуки для побочных эффектов и локального состояния.
Короткая заметка для команды (социальный анонс)
Добавили переиспользуемый React‑хук useFetch: отмена запросов, обработка ошибок и пример использования. Если нужно кеширование и retry — рассмотрите React Query.
КОНЕЦ. Надёжный хук для большинства простых сценариев загрузки данных и удобная отправная точка для перехода на более продвинутые библиотеки.
Похожие материалы
Unity Lights: циферблат Apple Watch для Black History Month
Обновление видеодрайвера для Rainbow Six Siege
Ограничение частоты запросов в ASP.NET Core
Исправление лагов Android: TRIM и LagFix
Семафоры в Bash: что это и как реализовать