Rules of Hooks
In this page:
function Component() {
// Top level only: not inside if, loops or nested functions
const [state, setState] = useState(initial);
useEffect(() => {}, []);
return <div />;
}
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.
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.
use so both React and other developers recognize it as one.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.
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 in your own terminal or Node.js environment.
- 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: