useEffect Hook
useEffect runs after React paints the screen. Use it for data fetching, timers, subscriptions, and syncing with non-React systems.
useEffect — side effects after render
useEffect runs after React paints the screen. Use it for data fetching, timers, subscriptions, and syncing with non-React systems.
Do not use useEffect for things you can compute during render — that belongs in plain JavaScript or useMemo.
Real-life example: useEffect is checking your mailbox after you finish cooking dinner — a separate task that happens after the main job (render) is done.
import { useState, useEffect } from "react";
function CourseList() {
const [courses, setCourses] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
let cancelled = false;
async function load() {
try {
const res = await fetch("/api/courses");
const data = await res.json();
if (!cancelled) setCourses(data);
} finally {
if (!cancelled) setLoading(false);
}
}
load();
return () => { cancelled = true; };
}, []);
if (loading) return <p>Loading...</p>;
return <ul>{courses.map((c) => <li key={c.id}>{c.title}</li>)}</ul>;
}Dependency array
[] runs once on mount. [userId] re-runs when userId changes. No array runs every render — rarely needed and often a bug.
Return a cleanup function to cancel timers, abort fetch, or remove listeners.
Real-life example: Dependencies are reminder alarms — [] means once on move-in day; [userId] means every time you change apartment roommate.
- [] — fetch initial data, add one-time listeners
- [dep] — refetch when dep changes
- cleanup — return function from useEffect