原文:useReducer, don't useStatehtml
本文難度:入門級別前端
本文默認你已經大概瞭解過 React Hooks,若是不瞭解能夠先看看 ReactJS 的文檔。react
當開發者們開始在他們的應用中使用 React Hooks API 時,不少人一開始都會把 useState 做爲他們的狀態管理工具。 然而,我強烈認爲 useReducer 比 useState 更適合作狀態管理。函數
首先我來定義一下『更適合』是什麼意思:工具
接下來我分別對三點進行闡述。測試
這篇文章大部分觀點只是個人主觀見解。spa
useState 有一個與 class 組件裏面的 setState 明顯不一樣的地方,那就是 useState 不對狀態作淺層合併了,而 useReducer 會合並。code
爲了說明這一點,我這裏給一個使用 useReducer 來實現『撤銷/重作』的例子:htm
function init(initialState) {
return {
past: [],
present: initialState,
future: [],
}
}
function reducer(state, action) {
const { past, future, present } = state
switch (action.type) {
case 'UNDO':
const previous = past[past.length - 1]
const newPast = past.slice(0, past.length - 1)
return {
past: newPast,
present: previous,
future: [present, ...future],
}
case 'REDO':
const next = future[0]
const newFuture = future.slice(1)
return {
past: [...past, present],
present: next,
future: newFuture,
}
default:
return state
}
}
複製代碼
用 useState 達到相同的效果有點困難,不過也並非不可能。我只是想告訴裏使用 useReducer 是多麼地方便,這也引出了第二點。blog
譯註:若是用 useState 來作,只須要把 past / present / future 放到同一個 state 裏面便可,可是會形成代碼分散。並且 useState 也不推薦你在一個 state 裏放太多東西,由於它不會合並 state,用起來不方便。
在 Web 開發中,咱們面對的問題不少時候並非純技術問題。大部分時候你都要跟其餘開發者工做,他們的開發經驗極可能跟你的很不同。
因爲大部分前端開發者都瞭解過 Redux,因此使用 useReducer 比使用 useState 更能快速得到收益。其核心概念好比 diapatch 一個 action,使用 reducer 來更新 state,都比 useState 更容易被這些開發者掌握。
還有一點值得注意,那就是即便你目前是一我的在開發一個應用,你也保不齊之後會有其餘人接手這份代碼。
要論 Hooks RFC、Twitter 裏被討論最多的話題,那就是如何測試 Hooks。我以爲要讓開發者理解測試 Hooks 的最佳實踐,仍是要花費一些時間的(譯註:尤爲是 useState)。可是若是你使用的是 useReducer,那麼你全部的跟 state 相關的業務邏輯代碼均可以放到一個單獨的函數裏,跟你的組件分開,很是好測試。
把狀態更新代碼和渲染邏輯分開,使得你能夠把測試代碼也分紅這兩部分。以上面的 reducer 代碼爲例, 咱們能夠輕鬆地測試撤銷和重作,作法是把 mock 狀態和 action 傳給 reducer 便可,咱們甚至不用引入 React!
test('it supports undoing the state', () => {
const state = { past: [{ count: 0 }], present: { count: 1 }, future: [] }
const newState = reducer(state, { type: 'UNDO' })
expect(newState.present.count).toBe(0)
})
複製代碼
我並不指望你們只使用 useReducer 不使用 useState,我我的也不會這麼作,它們各有各的使用場景。可是個人確認爲 useReducer 在複雜的狀態管理場景下比 useState 更好維護。