snippettypescriptreactModeratepending
React custom hook for async data fetching
Viewed 0 times
useFetchcustom-hookAbortControllerloadingerror-state
Problem
Fetching data in components requires repetitive loading/error state management and cleanup for race conditions.
Solution
Create a reusable useFetch hook:
import { useState, useEffect, useRef } from 'react';
function useFetch<T>(url: string) {
const [data, setData] = useState<T | null>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<Error | null>(null);
const abortRef = useRef<AbortController>();
useEffect(() => {
abortRef.current?.abort();
const controller = new AbortController();
abortRef.current = controller;
setLoading(true);
setError(null);
fetch(url, { signal: controller.signal })
.then(res => {
if (!res.ok) throw new Error(
return res.json();
})
.then(setData)
.catch(err => {
if (err.name !== 'AbortError') setError(err);
})
.finally(() => {
if (!controller.signal.aborted) setLoading(false);
});
return () => controller.abort();
}, [url]);
return { data, loading, error };
}
// Usage:
function UserProfile({ userId }) {
const { data, loading, error } = useFetch(
if (loading) return <Spinner />;
if (error) return <Error message={error.message} />;
return <Profile user={data} />;
}
import { useState, useEffect, useRef } from 'react';
function useFetch<T>(url: string) {
const [data, setData] = useState<T | null>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<Error | null>(null);
const abortRef = useRef<AbortController>();
useEffect(() => {
abortRef.current?.abort();
const controller = new AbortController();
abortRef.current = controller;
setLoading(true);
setError(null);
fetch(url, { signal: controller.signal })
.then(res => {
if (!res.ok) throw new Error(
HTTP ${res.status});return res.json();
})
.then(setData)
.catch(err => {
if (err.name !== 'AbortError') setError(err);
})
.finally(() => {
if (!controller.signal.aborted) setLoading(false);
});
return () => controller.abort();
}, [url]);
return { data, loading, error };
}
// Usage:
function UserProfile({ userId }) {
const { data, loading, error } = useFetch(
/api/users/${userId});if (loading) return <Spinner />;
if (error) return <Error message={error.message} />;
return <Profile user={data} />;
}
Why
This hook handles loading states, error states, and AbortController cleanup for race conditions when URL changes.
Revisions (0)
No revisions yet.