React
Beginner
1 min read
useFetch: Data Fetching as a Custom Hook
Example
import { useState, useEffect, useCallback } from 'react';
function useFetch(url, options = {}) {
const [data, setData ] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError ] = useState(null);
const fetchData = useCallback(async (signal) => {
setLoading(true);
setError(null);
try {
const res = await fetch(url, { ...options, signal });
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const json = await res.json();
setData(json);
} catch (err) {
if (err.name !== 'AbortError') setError(err.message);
} finally {
setLoading(false);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [url]);
useEffect(() => {
const controller = new AbortController();
fetchData(controller.signal);
return () => controller.abort();
}, [fetchData]);
return { data, loading, error, refetch: () => fetchData(new AbortController().signal) };
}
// ── Usage ──────────────────────────────────────────────────────────────────
function PostList() {
const { data: posts, loading, error, refetch } = useFetch('/api/posts');
if (loading) return <p>Loading…</p>;
if (error) return <p>Error: {error} <button onClick={refetch}>Retry</button></p>;
return (
<ul>
{posts.map(p => <li key={p.id}>{p.title}</li>)}
</ul>
);
}