2-14 React Hooks 不可這麼用

慣例上所有 React Hooks 的方法都會以 use 作為函式名稱的開頭,例如,useStateuseEffectuseCallback、...等等。現在雖然我們只提到了 useState,但在使用 React Hooks 的方法時有些原則一定要注意。

其中最重要的一個原則是:「不能在條件式(conditions)、迴圈(loops)或嵌套函式(nested functions)中呼叫 Hook 方法」。

什麼意思呢?以 useState 來說,這樣的寫法是正確的:

// ✅ 正確使用
const Counter = () => {
const [count, setCount] = useState();
return {
/* ... */
};
};

但如果因為某些原因而把 useState 放到 if 內時可能會導致嚴重錯誤:

// ❌ 錯誤使用,把 React Hooks 放到 if 內
const Counter = () => {
if (isValidCounter <= 10) {
const [count, setCount] = useState();
}
return {
/* ... */
};
};

要留意的是,以 use 開頭的函式不能放在判斷式內,不論是這裡提到的 useState 或者未來我們會學到的 useEffect, useMemo 等其他的 React Hooks 都需要遵循這個規範。

之所以會有這樣的規定是因 React 元件(例如,<Counter />)每次在轉譯或更新畫面時,都會呼叫產生這個元件的函式(Counter()),而在 React Hooks 中會去記錄這些 Hooks 在函式中被呼叫的順序,以確保資料能夠被相互對應,但若當我們將 Hooks 放到條件式或迴圈內時,就會破壞了這些 Hooks 被呼叫到的順序,如此將會造成錯誤。

雖然 useSomething 這類的 React Hooks 不能放在條件式中,但要留意的是,像這裡透過 useState() 產出的變數(count)和方法 setCount,則是可以在判斷式內使用的。例如:

const Counter = () => {
const [count, setCount] = useState();
// 透過 useState 取出來的方法,是可以放在條件式中使用的
if (/* 條件判斷 */) {
setCount(10)
}
return {
/* ... */
};
};