Lesson 11 of 20

useEffect Hook

Side Effects with useEffect

The useEffect hook lets you perform side effects in functional components — things like fetching data, setting up subscriptions, or manually changing the DOM. It runs after React renders the component.

The dependency array controls when the effect runs: no array means every render, empty array means mount only, and specific values mean it runs when those values change.

Example
import { useState, useEffect } from 'react';

function UserProfile({ userId }) {
  const [user, setUser] = useState(null);
  const [loading, setLoading] = useState(true);

  // Runs when userId changes
  useEffect(() => {
    setLoading(true);
    fetch(`https://api.example.com/users/${userId}`)
      .then(res => res.json())
      .then(data => {
        setUser(data);
        setLoading(false);
      });
  }, [userId]);

  // Runs once on mount
  useEffect(() => {
    document.title = 'User Profile';
  }, []);

  // Cleanup example (runs on unmount)
  useEffect(() => {
    const timer = setInterval(() => console.log('tick'), 1000);
    return () => clearInterval(timer); // Cleanup
  }, []);

  if (loading) return <p>Loading...</p>;
  return <h1>{user?.name}</h1>;
}
  • useEffect(() => {}) — Runs after every render
  • useEffect(() => {}, []) — Runs once on mount
  • useEffect(() => {}, [dep]) — Runs when dep changes
  • Return a cleanup function to run on unmount or before re-running
  • Common uses: data fetching, event listeners, timers, DOM updates
Notes
  • Always include all variables used inside useEffect in the dependency array. Missing dependencies can cause stale data bugs.