useEffect
Synchronizes a component with an external system by running side effects after render. Handles subscriptions, data fetching, DOM manipulation, and cleanup.
Signature
useEffect(setup: () => (() => void) | void, dependencies?: any[])Parameters
| Parameter | Type | Description |
|---|---|---|
| setup | () => (() => void) | void | A function that runs after render. May return a cleanup function that runs before the next effect execution or on unmount. |
| dependencies | any[] | 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
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>;
}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>;
}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
useLayoutEffectFires synchronously after all DOM mutations but before the browser paints. Used for reading layout and synchronously re-rendering to avoid visual flicker.
useInsertionEffectFires synchronously before any DOM mutations. Designed exclusively for CSS-in-JS libraries to inject styles before layout effects and effects read them.
useRefCreates a mutable ref object that persists across renders without triggering re-renders when its value changes. Commonly used for DOM access and storing mutable instance variables.
useCallbackReturns a memoized version of a callback function that only changes when its dependencies change. Prevents unnecessary re-renders of child components that receive callbacks as props.
More Effects & Lifecycle Hooks
Explore All React Hooks
Browse our complete reference of 19 React hooks with signatures, examples, pitfalls, and in-depth explanations.