學 React 的時候,你一定聽過一句規則:
Hooks 必須在最上層呼叫
不要放在 if / for / while / 條件式裡!
React 為什麼要這樣限制?
因為 React 是靠「呼叫順序」來對應 Hook 的狀態。
如果順序變了,React 就會對應錯位,整個 component 就壞掉。
在 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 才能一一對應到正確的狀態。
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]
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>;
}
❌「不用的時候也要呼叫 Hook,不是浪費嗎?」
✅ 沒錯,但這是必要的「規則成本」,換來的是 Predictability(可預測性)。
❌「我能在 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>;
}
答案:
英文
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 的順序一致。