Script Valley
React.js: Complete Course
React Hooks In DepthLesson 3.1

useEffect hook: side effects and lifecycle in functional components

useEffect syntax, dependency array, cleanup function, component mount/unmount, common side effects, stale closure with deps, effect on every render

useEffect for Side Effects

Side effects are anything that reaches outside React's rendering: API calls, subscriptions, timers, or direct DOM manipulation. useEffect runs after the component renders.

Three Patterns

import { useEffect, useState } from 'react';

function Demo() {
  const [count, setCount] = useState(0);

  // 1. Runs after EVERY render (no dep array)
  useEffect(() => {
    document.title = `Count: ${count}`;
  });

  // 2. Runs ONCE on mount (empty dep array)
  useEffect(() => {
    console.log('Component mounted');
  }, []);

  // 3. Runs when 'count' changes
  useEffect(() => {
    console.log('Count changed to', count);
  }, [count]);

  return <button onClick={() => setCount(c => c + 1)}>{count}</button>;
}

Cleanup Function

Return a cleanup function to cancel subscriptions or timers when the component unmounts or before the effect re-runs:

useEffect(() => {
  const timer = setInterval(() => {
    setCount(c => c + 1);
  }, 1000);

  return () => clearInterval(timer); // cleanup
}, []);

All values used inside an effect that come from the component scope must be listed in the dependency array. Missing dependencies cause stale closure bugs where the effect reads outdated values. ESLint's exhaustive-deps rule catches these automatically.

Up next

useRef hook: DOM access and mutable values in React

Sign in to track progress

useEffect hook: side effects and lifecycle in functional components โ€” React Hooks In Depth โ€” React.js: Complete Course โ€” Script Valley โ€” Script Valley