- 作者:老汪软件技巧
- 发表时间:2024-09-07 17:03
- 浏览量:
引言
本文将从状态管理的核心设计理念出发以及对观察者模式的简单实现,带领大家一步步探索 Zustand 的核心原理,并通过实际代码展示如何实现一个类似 Zustand 的状态管理库。本文采用面向对象的方式,方便读者更容易理解其背后的设计思路和实现细节
目标灵活应用观察者设计模式,解耦实项目中的数据流和逻辑掌握 Zustand 的核心设计理念,了解其简洁高效的状态管理方法通过 TypeScript 编写自定义的 Hooks,提升代码质量和类型安全性熟练使用 TypeScript 的高级类型特性,优化状态管理逻辑利用 useSyncExternalStore 优化状态管理的订阅与更新流程学会使用usRef防止一些没必要的渲染学会中间件开发思想观察者设计模式
在很多前端框架或库中,观察者模式随处可见。Vue、MobX、Promise、React-query 等库都通过观察者模式实现了数据的订阅与更新。观察者模式的核心思想就是 发布-订阅,即观察者订阅主题对象,当主题发生变化时,通知所有观察者进行相应的操作。
观察者模式的基本结构:
// 主题对象
class Subject {
private watchers: Set<Watcher>;
private state: T | null;
constructor(state: T) {
this.watchers = new Set();
this.state = state || null;
}
// 注册观察者
register(watcher: Watcher ) {
this.watchers.add(watcher);
}
// 移除观察者
remove(watcher: Watcher ) {
this.watchers.delete(watcher);
}
// 通知所有观察者
notify(newState: T, oldState: T) {
this.watchers.forEach(watcher => {
watcher.update(newState, oldState);
});
}
// 更新数据
update(newState: T) {
const oldState = this.state;
this.state = newState;
this.notify(newState, oldState);
}
}
// 观察者类
class Watcher {
private subscribe: (newVal: T, oldVal: T) => void;
constructor(subscribe: (newVal: T, oldVal: T) => void) {
this.subscribe = subscribe;
}
// 更新时执行回调
update(newVal: T, oldVal: T) {
if (newVal !== oldVal) {
this.subscribe(newVal, oldVal);
}
}
}
从观察者模式到Zustand
Zustand 的状态管理可以看作是观察者模式的最佳实践。它通过 store 持有应用状态,并提供 subscribe 方法供组件订阅变化,从而将状态管理逻辑和框架层面逻辑进行分离,为了更好地理解 Zustand 的实现原理,我们通过以下代码进行深度探索。
Zustand 整体逻辑架构图
实现 Store
Store 是状态管理的核心,它持有应用的状态,并通过 setState 方法来更新状态。当状态发生变化时,所有注册的观察者都会收到通知,并执行相应的操作
class Store {
private subject: Subject;
state: T;
constructor(state: T) {
this.subject = new Subject(state);
this.state = state;
}
getState(): T {
return this.state;
}
setState(partial: Partial, replace: boolean = false): void {
const oldState = this.state;
const newState = typeof partial === 'function' ? (partial as Function)(this.state) : partial;
if (Object.is(newState, oldState)) return;
if (replace) {
this.state = newState as T;
} else {
this.state = { ...oldState, ...newState } as T;
}
this.subject.update(this.state);
}
subscribe(callback: (newState: T, oldState: T) => void): () => void {
const watcher = new Watcher(callback);
this.subject.register(watcher);
return () => {
this.subject.remove(watcher);
};
}
}
实现createStore
createStore 函数负责创建 store 实例并提供给其他外界组件库使用的
function createStore(callback) {
const store = new Store();
store.state = callback(store.setState, store.getState, store.subscribe, store.removeState);
return (selector?): ReturnType<typeof selector> => {
return useStore(store, selector);
}
}
useStore实现一 useSyncExternalStore
useStore是react与zustand之间的桥梁。通过订阅 store 的变化,组件在状态更新时可以自动重新渲染
function useStore(store: Store): T;
function useStore(store: Store, selector) : ReturnType<typeof selector>
function useStore(store: Store, selector?: unknown) {
const getSnapshot = () => ( typeof selector === 'function' ? selector(store.getState()) : store.getState());
return useSyncExternalStore(
store.subscribe, // 订阅函数
getSnapshot, // 返回当前状态
getSnapshot // 在服务器渲染中使用相同的快照
);
}
实现二 useState
在并发渲染模式下,React 的状态订阅需要更加精确地控制。不能确保状态的一致性,解决潜在的状态读取滞后问题,特别是在** React 的并发模式和服务器端渲染(SSR**)中
function useStore(store: Store, selector?: unknown) {
const state = useRef();
const selectorFnRef = useRef(selector);
const selectorFn = selectorFnRef.current;
const [_,forceUpdate] = useState({});
store.subscribe((newState, oldState) => {
if (typeof selectorFn === 'function') {
const newValue = selectorFn(newState)
const oldValue = selectorFn(oldState);
if (newValue !== oldValue) {
state.current = newValue;
forceUpdate({})
}
} else {
state.current = newState
forceUpdate({})
}
})
return state.current;
}
结束语
通过本文的介绍,我们实现了一个基于观察者模式的状态管理系统,并且探讨了 zustand 底层设计的核心思想。zustand 之所以广受欢迎,正是因为它简洁的 API 和轻量的设计,避免了不必要的复杂度,非常适合中小型 React 项目的状态管理需求。