📖 Notes
LESSON 7 OF 18
useEffect — Side Effects & Lifecycle
Running Code in Response to Changes
useEffect handles anything that happens outside of rendering — fetching data, subscribing to events, or setting up a timer — and its dependency array controls exactly when it re-runs.
Dependency Array Controls Timing
Three Patterns
1️⃣
useEffect(fn, [])
Runs once, on mount.
2️⃣
useEffect(fn)
Runs after every render (rare, usually a mistake).
3️⃣
useEffect(fn, [filter])
Runs when "filter" changes.
🧹
Cleanup Function
Returned function runs before the next effect or on unmount.
Fetch on Mount + Cleanup
JSXimport { useState, useEffect } from "react";
function CourseList() {
const [courses, setCourses] = useState([]);
// Run on mount ([] = once)
useEffect(() => {
fetch("/api/courses")
.then(r => r.json())
.then(setCourses);
}, []);
// Run when filter changes
useEffect(() => {
console.log("Filter changed");
}, [filter]);
// Cleanup (timers, subscriptions)
useEffect(() => {
const timer = setInterval(() => tick(), 1000);
return () => clearInterval(timer); // cleanup!
}, []);
}
💡
The most common use
Fetching data once when a component mounts and storing it with useState — this exact pattern reappears constantly across React apps.