🚀zustand
为什么这么好用
第一次使用 zustand
被惊艳到了。只需要调用create
函数创建store
就可以直接在任何组件使用了。
💎 底层原理很简单
好奇的翻开代码,才发现 zustand
基于发布订阅模式实现的响应式。下面是核心代码实现。
function createStoreImpl(initialState) { let state = initialState; const listeners = new Set(); function setState(newState) { state = newState; listeners.forEach(listener => listener(state)); } function subscribe(listener) { listeners.add(listener); return () => { listeners.delete(listener); }; } function destroy() { listeners.clear() } return { getState: () => state, setState, subscribe, destroy }; }
使用方法如下:
// 创建 const store = createStoreImpl({ count: 0 }); // 更新 store.setState({ count: 1 }); // 订阅 const unsubscribe = store.subscribe((state) => { console.log('State changed:', state); }); store.setState({ count: 2 }); // 触发订阅的回调函数 unsubscribe(); // 取消订阅 store.setState({ count: 3 }); // 不会触发订阅的回调函数 store.destroy(); // 销毁这个store
💎 不同环境处理
事实上,zustand
提供了两个版本的包,即react版本和非react的 vanilla
版本。
包的 export 信息如下,可以看出默认为react版本,
export * from './vanilla.ts' export * from './react.ts' export { default } from './react.ts'
非react的环境使用如下
import { createStore } from 'zustand/vanilla' const store = createStore(() => ({ ... })) const { getState, setState, subscribe } = store export default store
在react模式下,和 vanilla
版本相同的是他们都是使用 createStore
创建的,使用 create
创建 store
和 vanilla
版本不同的是,createImpl
的返回值是使用 useStore
包装了一层的返回值(实际是 useSyncExternalStore api
)。
const createImpl = (createState) => { const api = typeof createState === 'function' ? createStore(createState) : createState const useBoundStore = (selector, equalityFn) => useStore(api, selector, equalityFn) Object.assign(useBoundStore, api) return useBoundStore } export const create = (createState) => createState ? createImpl(createState) : createImpl
useStore
又通过内置的包 use-sync-external-store/shim/with-selector
处理。
use-sync-external-store
可以在 Zustand
中使用外部状态管理库的状态,例如 Redux
。
import useSyncExternalStoreExports from 'use-sync-external-store/shim/with-selector' export function useStore<TState, StateSlice>( api: WithReact<StoreApi<TState>>, selector: (state: TState) => StateSlice = api.getState as any, equalityFn?: (a: StateSlice, b: StateSlice) => boolean ) { const slice = useSyncExternalStoreWithSelector( api.subscribe, api.getState, api.getServerState || api.getState, selector, equalityFn ) useDebugValue(slice) return slice }
🚀 总结
大概的调用流程图如下: