100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
React

The useEffect Hook

Understand useEffect for side effects in function components, covering the dependency array, cleanup functions, and effect timing.

Hooks FundamentalsIntermediate12 min readJul 8, 2026
Analogies

Introduction

useEffect lets function components perform side effects: operations that reach outside the pure render, such as fetching data, subscribing to events, manually manipulating the DOM, setting timers, or logging. It unifies the behavior previously split across componentDidMount, componentDidUpdate, and componentWillUnmount in class components into a single API driven by a dependency array.

🏏

Cricket analogy: useEffect is like the ground staff's off-field duties (covering the pitch, checking the sightscreen, logging weather) that happen alongside the match but aren't part of the actual batting or bowling, unifying what used to be separate pre-match, mid-match, and post-match checklists into one routine.

Syntax

jsx
useEffect(() => {
  // effect body: runs after the DOM has been updated

  return () => {
    // optional cleanup: runs before the next effect and on unmount
  };
}, [dependency1, dependency2]); // dependency array

Explanation

The dependency array controls when the effect re-runs. Omit it entirely and the effect runs after every render. Pass an empty array [] and the effect runs only once, after the first render (mount), mimicking componentDidMount. Pass an array with values ([count] or [userId]) and the effect re-runs only when any of those values changes between renders, using a shallow comparison (Object.is) per item; this mimics a filtered componentDidUpdate. If the effect function returns another function, React treats that returned function as a cleanup routine: it runs right before the effect runs again (using the previous render's values) and also runs once when the component unmounts. This is essential for avoiding memory leaks — canceling subscriptions, clearing timers, removing event listeners, and aborting fetch requests. Regarding timing, useEffect runs asynchronously after the browser has painted the updated DOM, so it does not block visual updates; this differs from useLayoutEffect, which fires synchronously before the browser paints, useful for DOM measurements that must happen before the user sees a flicker. A common pitfall is omitting values used inside the effect from the dependency array, which creates stale closures bugs; the exhaustive-deps ESLint rule from eslint-plugin-react-hooks helps catch these.

🏏

Cricket analogy: An empty dependency array is like a toss that happens once at the start of the match and never again (mount); a dependency on [score] re-runs the drinks-break announcement only when the score changes; the cleanup is like retiring the old ball before a new one is brought on, and useEffect firing after the crowd sees the replay mirrors async timing versus useLayoutEffect's instant DRS check before broadcast.

Example

jsx
function ChatRoom({ roomId }) {
  const [messages, setMessages] = useState([]);

  useEffect(() => {
    const connection = createConnection(roomId);
    connection.connect();
    connection.on('message', msg => {
      setMessages(prev => [...prev, msg]);
    });

    // Cleanup: disconnect before reconnecting to a new room or on unmount
    return () => connection.disconnect();
  }, [roomId]); // re-run only when roomId changes

  return (
    <ul>
      {messages.map((m, i) => <li key={i}>{m}</li>)}
    </ul>
  );
}

Output

When ChatRoom first mounts with roomId='general', the effect connects to the 'general' room and starts listening for messages. If the roomId prop changes to 'random', React first calls the cleanup function to disconnect from 'general', then re-runs the effect to connect to 'random'. When ChatRoom unmounts entirely, the cleanup runs one final time to close the connection, preventing a memory leak or messages being processed for an unmounted component.

🏏

Cricket analogy: When a broadcaster switches commentary from the Mumbai match to the Chennai match, they first sign off from Mumbai's feed (cleanup) before connecting to Chennai's live feed (re-run effect), and when the broadcast ends entirely, they disconnect from whichever feed is live, exactly like ChatRoom switching from 'general' to 'random' and cleaning up on unmount.

Key Takeaways

  • useEffect handles side effects: data fetching, subscriptions, timers, and manual DOM work.
  • No dependency array = runs after every render; [] = runs once on mount; [deps] = runs when any dependency changes.
  • Returning a function from the effect defines cleanup, which runs before the next effect execution and on unmount.
  • useEffect runs asynchronously after paint; useLayoutEffect runs synchronously before paint for cases needing pre-paint DOM measurement.
  • Omitting used values from the dependency array causes stale closures; the exhaustive-deps lint rule helps prevent this bug.

Practice what you learned

Was this page helpful?

Topics covered

#React#ReactJsStudyNotes#WebDevelopment#TheUseEffectHook#UseEffect#Hook#Syntax#Explanation#StudyNotes#SkillVeris