BRUCE_FEBRUCE_FE

EN/CH Mode

BRUCE_FE React Interview Notes - Hook Principles and Why Hook Calls Have Restrictions?

Deep dive into React Hooks' working principles and why specific calling rules must be followed. Understand how Hooks remember state in React, why they can't be used in conditionals, and the internal implementation of useState, useEffect, and useContext, including interview points and answers.

影片縮圖

Lazy to read articles? Then watch videos!

React Hooks Internal Implementation Principles

React calls function components on every render, but how are Hook states preserved? The secret lies in React maintaining adata structure (usually an array or linked list) outside the component to persist state.

Simplified Implementation Model of React Hooks

// Simplified Hook implementation model
let hooksArray = []; // Store Hook states
let currentHookIndex = 0;

// Simplified useState implementation
function useState(initialValue) {
  const index = currentHookIndex;
  
  // Initialize on first render
  if (hooksArray[index] === undefined) {
    hooksArray[index] = initialValue;
  }
  
  // Update function
  const setState = (newValue) => {
    hooksArray[index] = newValue;
    rerender(); // Trigger re-render
  };
  
  currentHookIndex++;
  return [hooksArray[index - 1], setState];
}

// ---------- Usage example ----------
function Counter() {
  // Each call increments currentHookIndex
  const [count, setCount] = useState(0);
  const [name, setName] = useState("John");
  
  // If using Hook in a condition
  if (count > 0) {
    // This will cause index confusion!
    const [flag, setFlag] = useState(false);
  }
  
  return { count, name, setCount };
}

Hooks Internal Storage Model

Component Rendering

MyComponent()

Execute Hook Calls

hooksArray

index: 0

25

index: 1

"John"

Now you can understand why Hook call order is so important: if Hooks are used in conditions, it leads toindex desynchronization, making React unable to correctly recall each Hook's previous state.

Why do React Hooks have fixed calling rules?

React Hooks must follow two main rules:

  • 1. Only call Hooks at the top level of React function components
  • 2. Don't call Hooks inside conditions, loops, or nested functions

These restrictions exist primarily because React relies on the Hook call orderto identify each Hook's state. React doesn't track Hooks by name or parameters, but by their callorder.

Hook Order Mechanism

On each render, React accesses Hooks in order:

function Profile() {
  // Hook #1
  const [name, setName] = useState("John");
  
  // Hook #2
  const [age, setAge] = useState(25);
  
  // Hook #3
  useEffect(() => {
    document.title = name;
  });
}

React Internal Storage (Can be understood as a List)

Hook #1 (index 0): [name, setName]
Hook #2 (index 1): [age, setAge]
Hook #3 (index 2): [effect function, dependencies]

What happens if we use Hooks in conditions?

function Profile(props) {
  const [name, setName] = useState("John"); // Always Hook #1
  
  if (props.showAge) {
    // Sometimes Hook #2, sometimes doesn't exist!
    const [age, setAge] = useState(25);
  }
  
  // This Hook is sometimes #2, sometimes #3
  // React gets confused and errors!
  useEffect(() => {
    document.title = name;
  });
}

React Internal Storage Confusion (Can be understood as a List)

When props.showAge = true:

Hook #1 (index 0): [name, setName]
Hook #2 (index 1): [age, setAge]
Hook #3 (index 2): [effect function, dependencies]

When props.showAge = false:

Hook #1 (index 0): [name, setName]
Hook #2 (index 1): [effect function, dependencies] ❌

⚠️ When conditions change, the Hook call order changes, React can't correctly map states, leading to errors.

🔥 Common Interview Questions

(1) Why can't we use Hooks in conditions?

Answer: React relies on the Hook call order to remember each Hook's state. Like standing in line, each Hook has a fixed position.

Correct usage:

function Counter() {
  const [name] = useState("John"); // Always the 1st
  const [count] = useState(0);     // Always the 2nd
  return <div>{name}: {count}</div>;
}

Incorrect usage:

function Counter() {
  const [name] = useState("John");
  
  if (name === "John") {
    const [flag] = useState(false); // Sometimes exists, sometimes doesn't!
  }
  
  const [count] = useState(0); // Position changes!
  return <div>{name}: {count}</div>;
}

Hook Order Confusion Diagram

First Render

useState('John') → position0

useState(false) → position1

useState(0) → position2

Second Render (condition false)

useState('John') → position0

❌ Conditional Hook skipped

useState(0) → Wrongly takes position1's value!