zustand - 基於Flux與hook實現狀態管理
目前狀態狀態管理的套件五花八門,尤其眾多是基於Redux架構而產出的套件的套件產物,然而隨著hook的流行,也開始出現了更易於使用的套件。以下讓我們來zustand這個神奇的套件吧。
關於zustand
官方稱這個套件是可擴張式的狀態管理解決方案,讓你透過hook的方式直覺的採用狀態管理。
有趣的是,他們在想要取代Redux的企圖心,相較其他套件是比較強烈的。
並且他們也整理出他們認為過往在Redux遇到了哪些問題想要設法改善
其中我覺得閒有餘力的話,可以參考Redux的這篇看看:Stale Props and “Zombie Children”
在去年FB前端社團有人分享這篇文章Stale props and zombie children in Redux
我覺得很適合讀,會從原始碼開始解析問題點
如何使用
在以前我們無論是使用Redux還是Context,都必須要做一些前置設定
不過zustand僅需要設計好hook後,即可馬上享用:
- 設計state hook
1 | import create from "zustand"; |
- 設計Component
1 | import useStore from "./hooks/useState"; |
這樣就可以使用了,沒錯,就這樣
以下我提供一個示範的範例,來試試看吧:
zustand能超越Redux和Context嗎
zustand的企圖心蠻明顯的,他們擺明就是要提出比Redux和Context更好的解決方案
讓我們來看看他的描述:
Why zustand over redux?
- Simple and un-opinionated
- Makes hooks the primary means of consuming state
- Doesn’t wrap your app in context providers
- Can inform components transiently (without causing render)
過往的經驗中,當我要教剛入手React的人如何進行狀態管理時
很常會遇到門檻較高的問題,因為他們可能沒有經歷過狀態管理的技術轉型過程
所以很難去理解這些功能為什麼會存在會這樣去設計,這些都是可以被理解的
不過zustand簡化了很多令新人匪夷所思的設計,不用wrap Provider, hook的用法……
Why zustand over context?
- Less boilerplate
- Renders components only on changes
- Centralized, action-based state management
用過Context的都知道事實上它並非狀態管理的解決方案
透過Dependency Injection的方式call to action取得資料,會額外產生不必要的re-render
並且管理起來也比較分散,不集中
zustand也正解決了這些問題
使用方式
我覺得官方文件寫的蠻清晰易懂的,不過這邊也可以提幾個出來
All state
1 | const state = useStore(); |
atomic state - 嚴格比較 strict
預設嚴格比較(old === new)
1 | const nuts = useStore(state => state.nuts) |
atomic state - 淺比較 shallow
shallow比較
1 | import shallow from 'zustand/shallow' |
atomic state - 控制渲染 control rerender
可以設計compare function來避免因為狀態導致的re-render
1 | const treats = useStore( |
Memorized Selector
推薦避免re-render的方式是搭配使用useCallback
function
1 | const fruit = useStore(useCallback(state => state.fruits[id], [id])) |
Async
非同步直接寫
1 | const useStore = create(set => ({ |
set與get
透過set與get,隨時更新取用資料
1 | const useStore = create((set, get) => ({ |
模擬redux
如果不習慣也能改成redux的寫法,真是有趣的設計是吧?
1 | const types = { increase: "INCREASE", decrease: "DECREASE" } |
關於Context
The store created with create doesn’t require context providers. In some cases, you may want to use contexts for dependency injection. Because the store is a hook, passing it as a normal context value may violate rules of hooks. To avoid misusage, a special createContext is provided.
在某些情境可能需要用到context,因此也提供類似的寫法:
1 | import create from 'zustand' |
小結
我覺得這是一個蠻有潛力的套件,更新頻率也蠻高的
儘管還沒打算用到,是很值得觀察的一個套件