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

Rules of Hooks

The Rules of Hooks are like a recipe's instruction to always add ingredients in the same order every time -- skip a step, and the whole dish comes out wrong.

Rule 1: Only Call Hooks at the Top Level

Hooks must be called in the same order every single render -- React uses this call order internally to associate each Hook call with its correct state. Putting a Hook inside a condition or loop can change that order between renders, corrupting React's internal bookkeeping.

Note: If you need conditional behavior, put the condition INSIDE the Hook (like inside useEffect's function body), not around the Hook call itself.

Warning: Code like if (condition) { const [x] = useState(0); } breaks this rule and causes confusing, hard-to-diagnose bugs.

Example: Rule 1: Only Call Hooks at the Top Level

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 Correct({ show }) {
      const [count, setCount] = React.useState(0); // always called, unconditionally
      if (!show) return null; // conditional logic AFTER the Hook call
      return <button onClick={() => setCount(count + 1)}>{count}</button>;
    }
    ReactDOM.createRoot(document.getElementById('root')).render(<Correct show={true} />);
  </script>
</body>
</html>

Rule 2: Only Call Hooks from React Functions

Hooks should only be called from within a React function component or from within a custom Hook (a function whose name starts with use). Calling them from a regular utility function or a class component's methods isn't supported and will cause errors.

Note: A custom Hook is just a regular function that happens to call other Hooks -- name it starting with use so both React and other developers recognize it as one.

Warning: Calling useState from a plain helper function (not a component, not a Hook) throws an 'Invalid hook call' error.

Example: Rule 2: Only Call Hooks from React Functions

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 useDoubled(value) { // valid custom Hook -- starts with "use"
      return React.useMemo(() => value * 2, [value]);
    }
    function Display({ n }) {
      const doubled = useDoubled(n);
      return <p>{n} doubled is {doubled}</p>;
    }
    ReactDOM.createRoot(document.getElementById('root')).render(<Display n={5} />);
  </script>
</body>
</html>

Enforcing the Rules with ESLint

The official eslint-plugin-react-hooks package automatically flags violations of both rules directly in your editor, catching most mistakes before you even run the code. Nearly every modern React project setup (Create React App, Vite templates) includes this plugin by default.

Note: Keep the react-hooks ESLint plugin enabled -- it catches subtle mistakes that are easy to miss just by reading code.

Warning: Disabling ESLint warnings for hooks rules 'to make an error go away' usually means a real bug is being hidden, not fixed.

Example: Installing the ESLint Hooks Plugin

bash
$ npm install --save-dev eslint-plugin-react-hooks

// .eslintrc.json
{
  "plugins": ["react-hooks"],
  "rules": {
    "react-hooks/rules-of-hooks": "error",
    "react-hooks/exhaustive-deps": "warn"
  }
}

⚠️ Run this command in your terminal.

Common Mistakes
  1. Calling a Hook inside an if statement, loop, or nested function instead of at the top level of the component.
  2. Calling Hooks from a regular JavaScript function instead of a React component or another custom Hook.
  3. Reordering or conditionally skipping Hook calls between renders, which breaks React's internal tracking.
Chapter Summary
  • Hooks must always be called at the top level of a component, never inside conditions or loops.
  • Hooks must only be called from React function components or other custom Hooks.
  • React relies on Hooks being called in the exact same order on every render.
  • The eslint-plugin-react-hooks package automatically catches most rule violations.
Browser Support

These rules apply to all Hooks introduced since 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.