TypeScript

Кастомный React-хук useFetch

Algonexys · 07.08.2026 · 👁 0

Загрузка данных с состояниями loading/error, отменой запроса при размонтировании и строгими типами.

Код

import { useCallback, useEffect, useState } from 'react';

interface State<T> {
  data: T | null;
  loading: boolean;
  error: Error | null;
}

export function useFetch<T>(url: string, options?: RequestInit) {
  const [state, setState] = useState<State<T>>({
    data: null, loading: true, error: null,
  });

  const load = useCallback(
    async (signal: AbortSignal) => {
      setState((s) => ({ ...s, loading: true, error: null }));
      try {
        const response = await fetch(url, { ...options, signal });
        if (!response.ok) throw new Error(`HTTP ${response.status}`);
        setState({ data: (await response.json()) as T, loading: false, error: null });
      } catch (error) {
        if ((error as Error).name === 'AbortError') return;
        setState({ data: null, loading: false, error: error as Error });
      }
    },
    [url],
  );

  useEffect(() => {
    const controller = new AbortController();
    void load(controller.signal);
    return () => controller.abort();   // отмена при размонтировании
  }, [load]);

  return state;
}

// const { data, loading, error } = useFetch<User[]>('/api/users/');