什么是 Zustand
Zustand
是一个轻量级的状态管理库,在写Leaf
Nest时需要使用到状态管理库所以了解了一下,相比于 Redux,Zustand
更加轻量和简单,一个简单的 demo
就能立刻明白如何使用了。(官网做的也真好看呐)
Zustand 在近年来所有新兴的状态管理库中算是最流行的之一,目前 Github
star 数已经超过了 50k,在 React 状态管理库中应该是仅次于
Redux(61k)。
所以花了点时间简单学习了一下 zustand,写了mini-zustand
实现核心功能。
mini-zustand
在 zustand 中核心功能代码主要在两个文件中:
- vanilla.ts
- createStoreImpl
的具体实现,包含了核心的状态管理逻辑,如:getState、setState、subscribe
等。
- react.ts
- 主要是 React 相关的逻辑,包含了 useStore 的具体实现。
- 使用了 React 的 useSyncExternalStore 来订阅 store 的变化。 >
这里扩展一下,useSyncExternalStore
是 React
18 新增的一个
Hook,用于订阅外部数据源的变化。它的主要作用是让我们可以在组件中订阅外部数据源(如:Redux、Zustand
等)的变化,并在数据源发生变化时自动更新组件。
vanilla.ts
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 = (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(state) : partial;
if (!Object.is(nextState, state)) { const prevState = state;
state = replace ?? (typeof nextState !== "object" || nextState === null) ? (nextState as TState) : Object.assign({}, state, nextState);
listeners.forEach((listener) => listener(state, prevState)); } };
const getState: StoreApi<TState>["getState"] = () => state;
const subscribe: StoreApi<TState>["subscribe"] = (listener) => { listeners.add(listener);
return () => listeners.delete(listener); };
const getInitialState: StoreApi<TState>["getInitialState"] = () => initialState;
const api = { setState, getState, subscribe, getInitialState }; const initialState = (state = createState(setState, getState, api)); return api; };
|
react.ts
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
| import React from "react"; import { createStore } from "./vanilla.ts"; import type { StoreApi } from "./vanilla.ts";
type ReadonlyStoreApi<T> = Pick<StoreApi<T>, "getState" | "getInitialState" | "subscribe">;
const identity = <T>(arg: T): T => arg; export function useStore(api); export function useStore(api, selector); 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 = (createState) => { const api = createStore(createState);
const useBoundStore: any = (selector?: any) => useStore(api, selector);
Object.assign(useBoundStore, api);
return useBoundStore; };
|
参考链接