Roadmap › React (with Hooks, React 19 & Next.js basics) › Module: Hooks in Depth
Lessons in this course (17)
7. useEffect: side effects, dependencies and cleanup
Intermediate★ Must knowLesson 7 of 17
jsx
function OrderDetails({ orderId }) {
const [order, setOrder] = useState(null);
const [error, setError] = useState(null);
useEffect(() => {
const controller = new AbortController();
setOrder(null);
fetch(`/api/orders/${orderId}`, { signal: controller.signal })
.then(r => { if (!r.ok) throw new Error(`HTTP ${r.status}`); return r.json(); })
.then(setOrder)
.catch(err => { if (err.name !== "AbortError") setError(err); });
return () => controller.abort(); // cleanup: runs before the next effect and on unmount
}, [orderId]); // re-run when orderId changes
if (error) return <p>Failed: {error.message}</p>;
return order ? <h2>{order.customer}</h2> : <Spinner />;
}| Dependency array | Runs |
|---|---|
| none | After every render |
[] | Once after mount (cleanup on unmount) |
[a, b] | After mount and whenever a or b changes (Object.is comparison) |
Rules: include every reactive value used inside (the ESLint rule enforces it); don't use effects for things computable during render ("you might not need an effect"); avoid setting state that triggers the same effect in a loop; prefer a data library (TanStack Query) or framework loaders for data fetching (caching, dedupe, race conditions). useLayoutEffect runs synchronously after DOM mutations before paint — for measuring layout.