React Essentials — Components, JSX, Props, State & MoreEntry 6 of 11
Rules of Hooks
Two rules that every hook call (useState, useEffect, custom hooks) must follow.
Notes
- Only call hooks inside component functions. Hooks must not be called outside React component functions (or custom hooks), for example at module level.
- Only call hooks at the top level. Hooks must not be called in nested code statements: not inside
ifstatements, loops, nested functions, or after an earlyreturn.
React identifies each hook by its call order on every render. If a condition skips a hook, every hook after it gets the wrong state. The eslint-plugin-react-hooks package enforces both rules. React 19's use() is the one exception; it may be called conditionally.
What / Why / When
- What
Constraints on where hooks may be called.
- Why
Hook state is tracked by position, not by name.
- When
Always, in every component and custom hook.
Code compare
import { useState } from "react";// Rule 1// ❌ Outside a component functionconst [val, setVal] = useState(0);// ✅ Inside a component functionfunction App() { const [val, setVal] = useState(0);}// Rule 2// ❌ Nested inside a conditionfunction App({ someCondition }: { someCondition: boolean }) { if (someCondition) { const [val, setVal] = useState(0); }}// ✅ At the top level; put the condition afterfunction App({ someCondition }: { someCondition: boolean }) { const [val, setVal] = useState(0); if (!someCondition) return null; return <p>{val}</p>;}Angular's closest parallel is the injection context. inject(), effect(), and toSignal() must run in a constructor or field initializer (or inside runInInjectionContext).
import { Component, effect, inject } from "@angular/core";import { HttpClient } from "@angular/common/http";@Component({ selector: "app-profile", template: "" })export class ProfileComponent { private http = inject(HttpClient); // ✅ field initializer constructor() { effect(() => { /* ... */ }); // ✅ constructor } load() { inject(HttpClient); // ❌ throws: outside the injection context }}Differences and gotchas
- Angular has no call-order rule. Its component class is instantiated once, while a React component function re-runs on every render.
Quick reference
| React | Angular |
|---|---|
| Hooks only in components/custom hooks | inject()/effect() only in injection context |
| Hooks at top level only | No ordering rule |
| Enforced by ESLint | Enforced by a runtime error |