您可能不知道關於 useState 的 7 件事
在為我們的專案(React)進行程式碼審查的時候,我常發現開發成員沒有意識到關於 useState
提供的一些好用功能或討厭的陷阱。雖然這些觀念不是什麼重大的啟發,但每一個使用 Hook 的人都應該要了解。
更新用的 setter 具有一致的參考
為了更具體的說明這點;所謂的更新 setter 就是陣列中的第二個函式,它們在每一次 render 時都會保持一致。因此您不需要將它們加入例如 useEffect
的相依參考。不要管 eslint-plugin-react-hooks 給出什麼警告。
1 | const [count, setCount] = useState(0); |
設定相同的狀態值,什麼也不會執行
useState
預設屬於 Pure Function (意指相同的輸入,永遠會得到相同的輸出,而且沒有任何顯著的副作用)。使用相同於當前的值執行更新函式不會有任何變化 - 不會更新 DOM,也不會刷新渲染,什麼事也沒有。
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
- 初始化可以使用 callback;
useState(() => initialValue)
- 當前狀態的更新建議使用 callback,尤其是搭配
useCallback
- React 彙整多次狀態更新成一次渲染的機制在某些情況下不會正確運作
參考
您可能不知道關於 useState 的 7 件事
https://andyyou.github.io/2021/09/29/seven-things-you-may-not-know-about-usestate/