← Back to React Course | Chapter 5: Core Hooks | Lesson 2 of 12

The Dependency Array

The dependency array is a checklist telling useEffect exactly which values to watch before deciding whether to run again.

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

markup
<!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

markup
<!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

markup
<!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>
Common Mistakes
  1. Leaving a variable used inside the effect out of the dependency array, causing it to use a stale value.
  2. Passing an empty array [] when the effect actually depends on props or state, hiding real bugs.
  3. 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.
Chapter Summary
  • 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.
Browser Support

No browser-specific restrictions -- dependency array behavior is consistent since Hooks' introduction in React 16.8.

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.