0Pricing
Frontend Academy · Lesson

useEffect Basics: Dependencies and Cleanup

Run side effects after render, control when they re-run with the dependency array, and return a cleanup function to avoid memory leaks.

useEffect Basics: Dependencies and Cleanup is a free Frontend Academy lesson on CoddyKit — lesson 1 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Frontend Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.

What Is useEffect?

useEffect runs a side effect after React renders. Side effects include: fetching data, subscribing to events, setting up timers, and interacting with external APIs. Effects run after the paint, not during rendering.

Basic Syntax

useEffect(effect, deps?). The effect function runs after every render by default. Provide a dependency array to control when it runs.

import { useEffect } from 'react';

function Component() {
  useEffect(() => {
    console.log('Ran after every render');
  });
}

Dependency Array Controls When Effect Runs

Empty array []: run once after mount. Non-empty array [a, b]: run when a or b changes. No array: run after every render (rarely what you want).

// Run once on mount:
useEffect(() => {
  fetchInitialData();
}, []);

// Run when userId changes:
useEffect(() => {
  fetchUser(userId);
}, [userId]);

// Run after every render (usually a bug):
useEffect(() => {
  trackPageView();
});

The Cleanup Function

Return a function from useEffect to run cleanup: remove event listeners, cancel subscriptions, clear timers. The cleanup runs before the next effect and on unmount.

useEffect(() => {
  const handleResize = () => setWidth(window.innerWidth);
  window.addEventListener('resize', handleResize);

  // Cleanup: remove listener when effect re-runs or component unmounts
  return () => {
    window.removeEventListener('resize', handleResize);
  };
}, []);

Stale Closures in Dependencies

Effects close over the values they reference at the time they were created. If you read a state or prop value inside an effect without listing it in dependencies, you'll see a stale value. ESLint's exhaustive-deps rule catches this.

ESLint exhaustive-deps Rule

The react-hooks/exhaustive-deps ESLint rule warns when you're missing effect dependencies. It's almost always correct to follow its suggestions — stale dependencies cause bugs.

useEffect vs useLayoutEffect

useEffect fires after the browser paints. useLayoutEffect fires synchronously after DOM mutations, before paint. Use useLayoutEffect for reading DOM measurements to avoid visual flicker.

Multiple Effects

Use multiple useEffect calls to separate unrelated concerns. Each effect can have its own dependency array and cleanup logic.

// Separate effects for separate concerns:
useEffect(() => { document.title = `${count} items`; }, [count]);
useEffect(() => {
  const sub = wsClient.subscribe(onMessage);
  return () => sub.unsubscribe();
}, []);

Race Conditions — The Ignore Flag

When an effect fetches data based on props, earlier requests may resolve after later ones. Use a cleanup flag to ignore stale responses.

useEffect(() => {
  let ignore = false;

  async function load() {
    const data = await fetchUser(userId);
    if (!ignore) setUser(data); // only update if not cleaned up
  }

  load();
  return () => { ignore = true; };
}, [userId]);

Strict Mode Double Effect

React 18 Strict Mode mounts, unmounts, and remounts components in development to surface cleanup bugs. Your effects will run twice — this is intentional and helps detect missing cleanup.

When Not to Use useEffect

Don't use useEffect to: 1) derive state from props (compute during render), 2) reset state on prop changes (use key prop), 3) update state unconditionally (causes loops). When in doubt, ask: does this code react to a user event or an external system?

Quick Check

When does a useEffect cleanup function run?

Recap: useEffect

Side effects run after render. Empty dep array = once on mount. Deps array = on specific changes. Return cleanup function to prevent leaks. Use multiple effects for separate concerns. The ignore flag prevents stale fetch responses. Strict Mode double-fires to test cleanup. Don't use useEffect for derived values or state you can compute in render.

Frequently asked questions

Is the “useEffect Basics: Dependencies and Cleanup” lesson free?

Yes — the full text of “useEffect Basics: Dependencies and Cleanup” is free to read here on the web, and the Frontend Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Frontend Academy course, upgrade to CoddyKit PRO.

What will I learn in “useEffect Basics: Dependencies and Cleanup”?

Run side effects after render, control when they re-run with the dependency array, and return a cleanup function to avoid memory leaks. You practise Frontend Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start Frontend Academy?

No prior experience is required. Frontend Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 1 of 4, so you can start here or from the beginning and move at your own pace.

How long does the “useEffect Basics: Dependencies and Cleanup” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this Frontend Academy lesson?

Yes. Every Frontend Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. useEffect Basics: Dependencies and Cleanup
  2. Fetching Data on Mount
  3. Handling Loading and Error States
  4. AbortController for Cleanup
← Back to Frontend Academy