Rules of Hooks
In this page:
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
<!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
<!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
$ 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.
- Calling a Hook inside an
ifstatement, loop, or nested function instead of at the top level of the component. - Calling Hooks from a regular JavaScript function instead of a React component or another custom Hook.
- Reordering or conditionally skipping Hook calls between renders, which breaks React's internal tracking.
- 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.
These rules apply to all Hooks introduced since React 16.8.
Chapter Quiz — Complete all 12 topics to unlock
0/12 topics done
Complete these topics first: