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

  1. Only call hooks inside component functions. Hooks must not be called outside React component functions (or custom hooks), for example at module level.
  2. Only call hooks at the top level. Hooks must not be called in nested code statements: not inside if statements, loops, nested functions, or after an early return.

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

React
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).

Angular
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

ReactAngular
Hooks only in components/custom hooksinject()/effect() only in injection context
Hooks at top level onlyNo ordering rule
Enforced by ESLintEnforced by a runtime error