React
useFetch
Write a useFetch hook that manages data fetching and loading state.
useFetch
useFetch is a hook that fetches data from a URL and returns data, loading, and error states. It collects repeated fetch logic in one place.
It uses three states: useState(null) for data, useState(true) for loading, useState(null) for error. Inside useEffect, fetch(url) is called; the returned promise is handled with .then and .catch.
Cleanup matters: if the component unmounts, the fetch is aborted with AbortController. Otherwise the state update hits a stale component and React warns. We use a simple cancelled flag here.
Cleanup flag
Updating state after a component unmounts warns in React. To prevent this, a let cancelled = false; flag is used; the cleanup function sets cancelled = true.
When the promise resolves, if (!cancelled) setData(...) only updates still-mounted components. This pattern is React's recommended approach for async work.
For advanced cases, AbortController cleanly aborts the fetch. But for simple apps, the cancelled flag is enough and clear.
Exercise useFetch skeleton
Complete the skeleton. Write a useFetch(url) hook. Define three states: data (null), loading (true), error (null). Inside useEffect, add let cancelled = false; flag, call fetch(url).then(r => r.json()).then(d => { if (!cancelled) { setData(d); setLoading(false); } }).catch(e => { if (!cancelled) { setError(e); setLoading(false); } }). Cleanup: () => { cancelled = true; }. Dependency [url]. Return [data, loading, error]. Export the hook.
Show example solution
import { useState, useEffect } from "react";
function useFetch(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
let cancelled = false;
fetch(url)
.then((r) => r.json())
.then((d) => {
if (!cancelled) {
setData(d);
setLoading(false);
}
})
.catch((e) => {
if (!cancelled) {
setError(e);
setLoading(false);
}
});
return () => { cancelled = true; };
}, [url]);
return [data, loading, error];
}
export default useFetch;
Test yourself
-
How many states does useFetch return?
Show answer
Three — useFetch returns three states.
-
Loading flag
useFetch starts loading as ____.
Show answer
useFetch starts loading as true.
-
Match the useFetch parts
- useState(null)
- data
- useState(true)
- loading
- fetch(url)
- Call
- cancelled
- Cleanup
Next lesson: useDebounce