iT邦幫忙

2025 iThome 鐵人賽

DAY 9
0
Modern Web

30 天掌握 React & Next.js:從基礎到面試筆記系列 第 9

Day 9 : 為什麼 Hooks 一定要寫在最上層

  • 分享至 

  • xImage
  •  

學 React 的時候,你一定聽過一句規則:

Hooks 必須在最上層呼叫
不要放在 if / for / while / 條件式裡!
React 為什麼要這樣限制?

因為 React 是靠「呼叫順序」來對應 Hook 的狀態
如果順序變了,React 就會對應錯位,整個 component 就壞掉。

Hooks 的運作原理(心智模型)

在 React 中,Hooks 並不是透過變數名稱來追蹤的,而是透過「呼叫順序」。

可以把它想像成一個 狀態格子的陣列(array-like slots)

第一次 render:
slot[0] → useState(0)
slot[1] → useEffect(...)
slot[2] → useState("Andy")

第二次 render:
React 依照呼叫順序重新對應:
slot[0] → 之前的 count
slot[1] → 之前的 effect
slot[2] → 之前的 name

這個「陣列」只是方便理解的心智模型(實際實作更複雜,不一定真的是 Array)。
但這樣思考有助於我們理解:

每次 render 時,Hooks 必須按照固定順序呼叫,這樣 React 才能一一對應到正確的狀態。

為什麼不能放在 if / loop?

錯誤範例(if 條件)

function Counter({ show }) {
  if (show) {
    const [count, setCount] = useState(0); // ❌ 只在 show=true 時才存在
  }
  const [name, setName] = useState("Andy");
}
  • show=true → Hooks 順序是 [count, name]
  • show=false → Hooks 順序是 [name]
  • 結果:React 對應錯位,直接報錯。

錯誤範例(loop)

function Example() {
  for (let i = 0; i < 3; i++) {
    const [value, setValue] = useState(i); // ❌ Hook 數量不固定
  }
  return null;
}

React 根本不知道這個迴圈會跑幾次,每次 render Hook 數量可能不同 → 對應混亂。

正確做法

永遠把 Hooks 放在 component 的最上層,保持呼叫順序一致。

function Counter({ show }) {
  const [count, setCount] = useState(0);   // ✅ 永遠在 slot[0]
  const [name, setName] = useState("Andy"); // ✅ 永遠在 slot[1]

  if (!show) return <div>No counter</div>;
  return <button onClick={() => setCount(count + 1)}>{count}</button>;
}

常見誤解

  1. ❌「不用的時候也要呼叫 Hook,不是浪費嗎?」
    ✅ 沒錯,但這是必要的「規則成本」,換來的是 Predictability(可預測性)

  2. ❌「我能在 helper function 裡呼叫 Hook 嗎?」
    ✅ 可以,但前提是這個 helper function 每次 render 都會被呼叫,且呼叫次數固定
    這就是為什麼 custom hook 可以正常運作。

小練習

判斷以下程式碼哪些會出錯:

// A
function Example({ show }) {
  if (show) {
    const [count, setCount] = useState(0);
  }
  return null;
}

// B
function Example() {
  const [count, setCount] = useState(0);
  if (count > 0) {
    const [name, setName] = useState("Andy");
  }
  return null;
}

// C
function Example() {
  const [count, setCount] = useState(0);
  return <button onClick={() => setCount(count + 1)}>{count}</button>;
}

答案:

  • A ❌
  • B ❌
  • C ✅

面試回答模板

英文

Hooks rely on the order in which they are called.
React doesn’t track them by name, but by their call position in the component.
If you put a hook inside a loop or condition, the order changes between renders and React can’t match them correctly.
That’s why hooks must always be called at the top level of a component.

中文

React 是靠「呼叫順序」來追蹤 Hook,而不是變數名稱。
如果你把 Hook 放在條件或迴圈裡,每次 render 順序可能不同,React 就會對應錯位,導致錯誤。
所以 Hook 必須放在最上層,確保每次 render 的順序一致。

總結

  • React 用「呼叫順序」追蹤 Hooks。
  • 可以把它想像成「狀態格子的陣列」,但這只是心智模型,實際實作更複雜。
  • Hooks 順序必須固定,不能放在 if / loop / 條件裡。
  • Custom hook 之所以可行,是因為它本質上還是固定順序的函式呼叫。

上一篇
Day 8:React Hook 是什麼?Hook 解決了哪些問題?
下一篇
Day 10 : 什麼是 useEffect?
系列文
30 天掌握 React & Next.js:從基礎到面試筆記10
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言