Effects & Lifecycle

useEffect

Synchronizes a component with an external system by running side effects after render. Handles subscriptions, data fetching, DOM manipulation, and cleanup.

Signature

TypeScript
useEffect(setup: () => (() => void) | void, dependencies?: any[])

Parameters

ParameterTypeDescription
setup() => (() => void) | voidA function that runs after render. May return a cleanup function that runs before the next effect execution or on unmount.
dependenciesany[]Optional array of reactive values. The effect re-runs only when a dependency changes. Omit to run after every render; pass [] to run only on mount.

Return Value

undefined — useEffect does not return a value.

Examples

Data Fetching
import { useState, useEffect } from 'react';

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

  useEffect(() => {
    let cancelled = false;
    setLoading(true);

    fetch(`/api/users/${userId}`)
      .then(res => res.json())
      .then(data => {
        if (!cancelled) {
          setUser(data);
          setLoading(false);
        }
      });

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

  if (loading) return <div>Loading...</div>;
  return <div>{user?.name}</div>;
}
Event Listener Subscription
import { useState, useEffect } from 'react';

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

  useEffect(() => {
    const handleResize = () => {
      setSize({ width: window.innerWidth, height: window.innerHeight });
    };

    window.addEventListener('resize', handleResize);
    return () => window.removeEventListener('resize', handleResize);
  }, []);

  return <p>{size.width} × {size.height}</p>;
}
Document Title Sync
import { useEffect } from 'react';

function PageTitle({ title }: { title: string }) {
  useEffect(() => {
    const previous = document.title;
    document.title = title;
    return () => { document.title = previous; };
  }, [title]);

  return null;
}

// Usage: <PageTitle title="Dashboard — MyApp" />

Common Pitfalls

!

Forgetting to include a variable in the dependency array, causing the effect to use stale values from a previous render.

!

Not returning a cleanup function for subscriptions or timers, leading to memory leaks.

!

Using an object or array literal as a dependency — these create new references every render and cause infinite re-runs.

!

Fetching data without handling the race condition when the component unmounts or dependencies change before the fetch completes.

Understanding useEffect

useEffect is React's primary mechanism for performing side effects in function components. It replaces the lifecycle methods componentDidMount, componentDidUpdate, and componentWillUnmount from class components, unifying them into a single, declarative API. Effects run after the browser has painted the screen, ensuring they don't block visual updates.

The dependency array is the key to controlling when effects re-run. An empty array [] means the effect runs once on mount and cleans up on unmount — perfect for subscriptions and one-time setup. Including specific values means the effect re-runs whenever those values change. Omitting the array entirely causes the effect to run after every render, which is rarely what you want.

Cleanup functions are critical for preventing memory leaks and stale behavior. When you subscribe to an event, start a timer, or open a WebSocket connection, you must return a cleanup function that tears down the subscription. React calls your cleanup before running the effect again and before unmounting the component. This pattern ensures resources are properly released.

A common pattern with data fetching is the cancelled/ignore flag. Since effects are asynchronous, a fetch started by one render might complete after the component has re-rendered with different props. By using a boolean flag that the cleanup sets to true, you can prevent setting state on an outdated response. Modern React applications often use libraries like TanStack Query or SWR that handle these edge cases automatically.

Related Hooks

More Effects & Lifecycle Hooks

Explore All React Hooks

Browse our complete reference of 19 React hooks with signatures, examples, pitfalls, and in-depth explanations.