Data

useFetch

Declarative fetch (MDN, opens in a new tab) with loading and error status.

Demo

url
…/posts/1
loading
true
error
null
data
null

fetching…

Usage

use-fetch.tsxtsx
import { useFetch } from "hookli";

type Post = { id: number; title: string; body: string };

export function Demo() {
  const { data, loading, error } = useFetch<Post>(
    "https://jsonplaceholder.typicode.com/posts/1",
  );

  if (loading) return <p>Loading…</p>;
  if (error) return <p>Request failed: {error.message}</p>;

  return <article>{data?.title}</article>;
}

API

useFetch.d.tsts
useFetch<T>(url: string): { data: T | null; loading: boolean; error: Error | null }

Parameters

NameTypeDefaultDescription
urlstringThe endpoint to GET. The request starts on mount and re-runs whenever the url changes.

Returns

NameTypeDescription
dataT | nullThe parsed JSON body; null until the first request succeeds. Kept from the previous url while a refetch is in flight.
errorError | nullSet on network failure or a non-ok response ("HTTP error! status: 404"). Never cleared by later requests — remount the component (e.g. key={url}) for fresh state.
loadingbooleanTrue until the first request settles. Not reset to true when the url changes — remount for a per-request loading flag.

Hook

The implementation, straight from hookli. Copy it, or install the package.

src/hooks/useFetch.hook.tstsx
import { useEffect, useState } from "react";

interface UseFetchResponse<T = any> {
  data: T | null;
  error: Error | null;
  loading: boolean;
}

export const useFetch = <T>(url: string): UseFetchResponse<T> => {
  const [data, setData] = useState<T | null>(null);
  const [error, setError] = useState<Error | null>(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    const fetchData = async () => {
      try {
        const response = await fetch(url);
        if (!response.ok) {
          throw new Error(`HTTP error! status: ${response.status}`);
        }
        const fetchedData = await response.json();
        setData(fetchedData);
      } catch (err) {
        setError(err as Error);
      } finally {
        setLoading(false);
      }
    };

    fetchData();
  }, [url]);

  return { data, error, loading };
};

View source on GitHub

Related hooks