介绍
Zustand是最近比较火的状态管理库,是Redux的替代品,相比于Redux,它的api简单,样板代码少,包体积小只有1.2KB(minified),基于hooks来管理状态以及生态也比较丰富,有immer、persist、redux等中间件。
原理
src/vanilla.ts中的代码如下,vanilla的意思是这里导出的createStore各框架都能用,而非仅限于React。
源码比较简单,核心是基于发布订阅模式和useSyncExternalStore实现的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| const createStoreImpl: CreateStoreImpl = (createState) => { type TState = ReturnType<typeof createState> type Listener = (state: TState, prevState: TState) => void let state: TState const listeners: Set<Listener> = new Set()
const setState: StoreApi<TState>['setState'] = (partial, replace) => { const nextState = typeof partial === 'function' ? (partial as (state: TState) => TState)(state) : partial if (!Object.is(nextState, state)) { const previousState = state state = (replace ?? (typeof nextState !== 'object' || nextState === null)) ? (nextState as TState) : Object.assign({}, state, nextState) listeners.forEach((listener) => listener(state, previousState)) } }
const getState: StoreApi<TState>['getState'] = () => state
const getInitialState: StoreApi<TState>['getInitialState'] = () => initialState
const subscribe: StoreApi<TState>['subscribe'] = (listener) => { listeners.add(listener) return () => listeners.delete(listener) }
const api = { setState, getState, getInitialState, subscribe } const initialState = (state = createState(setState, getState, api)) return api as any }
export const createStore = ((createState) => createState ? createStoreImpl(createState) : createStoreImpl) as CreateStore
|
在React中集成
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| export function useStore<TState, StateSlice>( api: ReadonlyStoreApi<TState>, selector: (state: TState) => StateSlice = identity as any, ) { const slice = React.useSyncExternalStore( api.subscribe, () => selector(api.getState()), () => selector(api.getInitialState()), ) React.useDebugValue(slice) return slice }
const createImpl = <T>(createState: StateCreator<T, [], []>) => { const api = createStore(createState)
const useBoundStore: any = (selector?: any) => useStore(api, selector)
Object.assign(useBoundStore, api)
return useBoundStore }
export const create = (<T>(createState: StateCreator<T, [], []> | undefined) => createState ? createImpl(createState) : createImpl) as Create
|
可以看到,Zustand是对useSyncExternalStore进行了封装,将状态统一管理在组件外部,避免了层层传递 Props。这种方式使得状态管理更加灵活,开发过程更加高效。
与Redux的对比
- Zustand相对于Redux需要较少的代码,并且上手成本低
- 定义衍生状态,Redux通过自定义hook/或者mapStateToProps实现,Zustand可以定义computed属性,相对来说比较方便。
- Redux是单一store,Zustand可以是多Store
与MobX的对比
- 没有computed缓存
- 更新粒度没有MobX细,开发时需要考虑如何避免重复渲染。
- 代码相对于MobX Store来说不够直观
- 体积小,Zustand + immer之后是14KB,mobx + mobx-react + mobx-react-lite是35KB
- 设置新状态需要用set(state => newState)的方式,没有MobX来的直接并且符合直觉。
- 避免re-render不需要selector,心智负担更小,代码量更少。
如果不考虑体积,我觉得可以直接选MobX。