AtomLearnAtomLearn
DashboardGoalsPathAchievementsReviewSign In
ReactNot Started

useEffect

Side effects in function components — when and how to use useEffect

0%
Knowledge0%
Learn & Drill
Fluency0%
Drill & Speed
Retention0%
Mastery & Review
Confidence0%
All modes
Practice

Free tier: read the explanation here. Upgrade to Pro for Drills, Speed challenges & Mastery badges.

Upgrade
Knowledge
Fluency
Retention

Knowledge Debt detected

You can study this freely — but your score may plateau if these foundations have gaps. The Mastery badge requires them to be solid.

Explanation

useEffect lets you run s after a component renders — data fetching, subscriptions, timers, direct DOM access. The means run once on mount; omitting it means run after every render]controls when the effect runs.

jsx
import { useEffect } from 'react';

useEffect(() => {
  // runs after render
}, [dependencies]);

Dependency array controls when it runs:

  • No array: runs after every render
  • Empty array `[]`: runs once after the first render (mount)
  • `[a, b]`: runs when a or b change
jsx
useEffect(() => { document.title = count; });          // every render
useEffect(() => { fetchInitialData(); }, []);           // once on mount
useEffect(() => { fetchUser(userId); }, [userId]);      // when userId changes

Cleanup function — return a function to clean up subscriptions, timers, etc.: ``jsx useEffect(() => { const id = setInterval(() => setTime(Date.now()), 1000); return () => clearInterval(id); // runs on unmount (or before re-running effect) }, []);

React StrictMode calls effects twice in development (mounts → unmounts → mounts) to help detect missing cleanup.

Common mistake: adding a function to the dependency array that is re-created every render → infinite loop. Use useCallback or move the function inside the effect.

Examples

Data fetching on mount

Re-fetch whenever postId changes by including it in the dependency array

function PostDetail({ postId }) {
  const [post, setPost] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    setLoading(true);
    fetch(`/api/posts/${postId}`)
      .then(r => r.json())
      .then(data => { setPost(data); setLoading(false); });
  }, [postId]);  // re-fetch when postId changes

  if (loading) return <Spinner />;
  return <Article post={post} />;
}

Cleanup: event listener

Always remove event listeners in the cleanup function to prevent memory leaks

function WindowSize() {
  const [size, setSize] = useState({ w: window.innerWidth, h: window.innerHeight });

  useEffect(() => {
    const handler = () => setSize({ w: window.innerWidth, h: window.innerHeight });
    window.addEventListener('resize', handler);
    return () => window.removeEventListener('resize', handler);  // cleanup!
  }, []);  // attach once, cleanup on unmount

  return <p>{size.w} × {size.h}</p>;
}

How well did you understand this?

Next in React

Forms in React

Continue