📖 Notes LESSON 7 OF 18

useEffect — Side Effects & Lifecycle

⏱️ 28 min
⚛️ React

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.

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
JSX
import { 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.
🗒 Cheat Sheet 📝 Worksheet