The Dependency Array
In this page:
Running an Effect Once on Mount
Passing an empty array [] as the second argument tells React this effect has no dependencies that would require it to re-run -- so it only runs once, right after the component's first render. This is commonly used for one-time setup like fetching initial data.
Note: An empty dependency array is the standard way to replicate 'run once when the component appears' behavior.
Warning: If your effect actually uses a prop or state value but you still pass [], that value will be stuck at its initial value inside the effect (a stale closure).
Example: Running an Effect Once on Mount
<!DOCTYPE html>
<html>
<head>
<script src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
</head>
<body>
<div id="root"></div>
<script type="text/babel">
function WelcomeOnce() {
React.useEffect(() => {
console.log("This runs only once, when the component first appears.");
}, []);
return <p>Check the console -- the message logs only once.</p>;
}
ReactDOM.createRoot(document.getElementById('root')).render(<WelcomeOnce />);
</script>
</body>
</html>
Re-running When a Value Changes
Listing a variable in the dependency array tells React to compare it between renders and re-run the effect only when it's different from before. This lets you react specifically to changes in one piece of state or props, ignoring unrelated re-renders.
Note: Include every value from component scope that the effect actually uses -- this keeps the effect correctly in sync with what it depends on.
Warning: Forgetting to list a value the effect uses is one of the most common React bugs -- ESLint's react-hooks plugin catches most of these automatically.
Example: Re-running When a Value Changes
<!DOCTYPE html>
<html>
<head>
<script src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
</head>
<body>
<div id="root"></div>
<script type="text/babel">
function UserWatcher({ userId }) {
React.useEffect(() => {
console.log("Fetching data for user:", userId);
}, [userId]);
return <p>Watching user {userId}</p>;
}
function App() {
const [id, setId] = React.useState(1);
return <div><UserWatcher userId={id} /><button onClick={() => setId(id + 1)}>Next User</button></div>;
}
ReactDOM.createRoot(document.getElementById('root')).render(<App />);
</script>
</body>
</html>
No Dependency Array vs Empty Array
These two forms look similar but behave very differently: omitting the array entirely runs the effect after every render, while passing an empty array [] runs it only once. Confusing these two is a frequent source of bugs -- one causes excessive re-running, the other can cause stale data.
Note: If you're not sure which to use, start by listing the actual values your effect reads, rather than defaulting to one of the two extremes.
Warning: Missing the array entirely (not even an empty one) is easy to do by accident and silently changes your effect's behavior.
Example: No Dependency Array vs Empty Array
<!DOCTYPE html>
<html>
<head>
<script src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
</head>
<body>
<div id="root"></div>
<script type="text/babel">
function Comparison() {
const [count, setCount] = React.useState(0);
React.useEffect(() => { console.log("Runs every render"); });
React.useEffect(() => { console.log("Runs once only"); }, []);
return <button onClick={() => setCount(count + 1)}>{count}</button>;
}
ReactDOM.createRoot(document.getElementById('root')).render(<Comparison />);
</script>
</body>
</html>
- Leaving a variable used inside the effect out of the dependency array, causing it to use a stale value.
- Passing an empty array
[]when the effect actually depends on props or state, hiding real bugs. - Putting a newly-created object or array literal in the dependency array, causing the effect to re-run every render since it's never equal to the previous one.
- The dependency array is the second argument to useEffect.
- React re-runs the effect only when one of the listed values has changed since the last render.
- An empty array
[]means the effect runs only once, after the first render. - Omitting the array entirely makes the effect run after every render.
No browser-specific restrictions -- dependency array behavior is consistent since Hooks' introduction in React 16.8.
Chapter Quiz — Complete all 12 topics to unlock
0/12 topics done
Complete these topics first: