您可能不知道關於 useState 的 7 件事
在為我們的專案(React)進行程式碼審查的時候,我常發現開發成員沒有意識到關於
useState
提供的一些好用功能或討厭的陷阱。雖然這些觀念不是什麼重大的啟發,但每一個使用 Hook 的人都應該要了解。
更新用的 setter 具有一致的參考
為了更具體的說明這點;所謂的更新 setter 就是陣列中的第二個函式,它們在每一次 render 時都會保持一致。因此您不需要將它們加入例如
useEffect
的相依參考。不要管
eslint-plugin-react-hooks
給出什麼警告。
1 |
const [count, setCount] = useState(0); |
設定相同的狀態值,什麼也不會執行
1 |
const [isOpen, setOpen] = useState(props.initOpen); |
但是對於物件不適用:
1 |
const [{ isOpen }, setState] = useState({ isOpen: true }); |
回傳
undefined
狀態
這表示
setState
可以直接從
useEffect
箭頭函式中回傳。警告:Effect 參數函式不能回傳除了清除用的函式以外的東西
1 |
useLayoutEffect(() => { |
useState 即 useReducer
事實上,
useState
在 React 內部的實作類似於一個
useReducer
,只是搭配一個預先定義的 reducer ,至少在 17.0 版本開始是這樣。參考
原始碼
。如果有人聲稱
useReducer
有更進階的技術優勢,他是騙人的。
您可以使用 callback 初始化狀態
1 |
const [style, setStyle] = useState(() => ({ |
您可以在初始化函式中使用
props
。坦白說,這有點過度優化。您都可以建立一堆 vDOM 了,為啥要擔心一個物件?不過對於繁重的初始化邏輯這的確有幫助。
另外,如果您想要在狀態使用函式,您可以額外在包一層函式
useState(() => () => console.log('gotcha!'))
您可以使用 callback 更新狀態
Callback 函式也可以用來更新狀態;像一個沒有 action 的 reducer。由於當前的狀態和閉包的狀態值可能不同
1 |
const [clicks, setClicks] = useState(0); |
比較正確的作法
1 |
const [isDown, setIsDown] = useState(false); |
一個狀態更新 = 一次非同步的渲染
React 有一個功能稱為 batching,它會強制多個
setState
調用彙整成一次渲染,但不總是如預期的運作。我們來看一下下面的程式碼:
1 |
console.log('render'); |
當您呼叫
onClick
的時候,會渲染幾次取決於您如何調用。查看
範例
<button onClick={onClick}>
會正確彙整成一次渲染
useEffect(onClick, [])
也會正確彙整
setTimeout(onClick, 100)
就會觸發額外的渲染
el.addEventListener('click', onClick)
也
不會
正確彙整成一次渲染
這些在 React 18 會
更新
,在這之前您需要使用
unstable_batchedUpdates
來強制彙整
1 |
import {unstable_batchedUpdates} from 'react-dom'; |
[state, setState] = useState()
的
setState
每次渲染參考都一樣
setState(currentValue)
不會做任何事。
if (value !== currentValue)
可以省略。
useEffect(() => setState(true))
不會破壞 Effect 清除功能
useState
內部的實作是一個預先定義 reducer 的
useReducer
useState(() => initialValue)
useCallback