引言:为什么我们需要另一个状态管理库?
在React生态系统中,状态管理一直是一个热门话题。从Redux、MobX到Zustand、Jotai,每个库都有其独特的哲学和适用场景。但你是否曾想过,这些状态管理库是如何工作的?为什么有些库性能更好?今天,我们将从零开始构建一个轻量级、高性能的React状态管理库,深入理解其核心原理。
通过这个实践项目,你不仅能够掌握状态管理的底层机制,还能学习到:
- React Hooks的高级用法
- 发布-订阅模式的实现
- 性能优化的关键技巧
- TypeScript类型系统的深度应用
第一部分:设计理念与架构
1.1 核心需求分析
在开始编码之前,我们需要明确我们的状态管理库应该具备哪些特性:
- 轻量级:包体积小,无冗余依赖
- 高性能:最小化不必要的重渲染
- TypeScript友好:完整的类型推断
- 简单易用:API设计直观,学习成本低
- 响应式更新:状态变更自动触发组件更新
1.2 架构设计
我们将采用基于Hooks的原子状态模型,每个状态都是独立的"原子",组件可以订阅特定的原子状态,只有当订阅的状态发生变化时,组件才会重新渲染。
// 核心架构示意图
// Store (全局状态容器)
// ├── Atom 1 (状态原子1)
// │ └── Subscribers (订阅者列表)
// ├── Atom 2 (状态原子2)
// │ └── Subscribers (订阅者列表)
// └── Atom N (状态原子N)
// └── Subscribers (订阅者列表)
第二部分:核心实现
2.1 状态原子(Atom)的实现
状态原子是我们库的最小单位,它包含状态值和订阅者列表。
// types.ts
export type Atom<T> = {
key: string;
value: T;
subscribers: Set<() => void>;
};
export type SetStateAction<T> = T | ((prev: T) => T);
// atom.ts
export function createAtom<T>(initialValue: T, key?: string): Atom<T> {
return {
key: key || Symbol('atom').toString(),
value: initialValue,
subscribers: new Set(),
};
}
2.2 全局状态容器(Store)
我们需要一个全局容器来管理所有的状态原子。
// store.ts
class Store {
private atoms: Map<string, Atom<any>> = new Map();
// 注册原子
register<T>(atom: Atom<T>) {
this.atoms.set(atom.key, atom);
}
// 获取原子
getAtom<T>(key: string): Atom<T> | undefined {
return this.atoms.get(key);
}
// 更新原子状态
setAtomValue<T>(key: string, newValue: T) {
const atom = this.atoms.get(key);
if (!atom) {
throw new Error(`Atom with key "${key}" not found`);
}
const oldValue = atom.value;
atom.value = newValue;
// 值发生变化时通知所有订阅者
if (!Object.is(oldValue, newValue)) {
atom.subscribers.forEach(subscriber => subscriber());
}
}
// 订阅原子变化
subscribe<T>(key: string, callback: () => void) {
const atom = this.atoms.get(key);
if (!atom) {
throw new Error(`Atom with key "${key}" not found`);
}
atom.subscribers.add(callback);
// 返回取消订阅函数
return () => {
atom.subscribers.delete(callback);
};
}
}
// 创建全局单例Store
export const globalStore = new Store();
2.3 React Hooks集成
现在让我们创建React Hooks,使组件能够与我们的状态管理系统交互。
// hooks.ts
import { useEffect, useRef, useState, useCallback } from 'react';
import { globalStore } from './store';
import type { Atom, SetStateAction } from './types';
// 创建状态原子的Hook
export function useAtom<T>(initialValue: T, key?: string): [T, (value: SetStateAction<T>) => void] {
const atomRef = useRef<Atom<T> | null>(null);
// 初始化或获取原子
if (!atomRef.current) {
atomRef.current = {
key: key || Symbol('atom').toString(),
value: initialValue,
subscribers: new Set(),
};
globalStore.register(atomRef.current);
}
const [state, setState] = useState<T>(atomRef.current.value);
// 订阅原子变化
useEffect(() => {
const unsubscribe = globalStore.subscribe(
atomRef.current!.key,
() => {
setState(atomRef.current!.value);
}
);
return unsubscribe;
}, []);
// 更新状态的函数
const setAtomValue = useCallback((value: SetStateAction<T>) => {
if (!atomRef.current) return;
const newValue = typeof value === 'function'
? (value as (prev: T) => T)(atomRef.current.value)
: value;
globalStore.setAtomValue(atomRef.current.key, newValue);
}, []);
return [state, setAtomValue];
}
// 选择器Hook:用于派生状态
export function useAtomSelector<T, R>(
atomKey: string,
selector: (state: T) => R,
deps: any[] = []
): R {
const [selectedState, setSelectedState] = useState<R>(() => {
const atom = globalStore.getAtom<T>(atomKey);
return atom ? selector(atom.value) : undefined as any;
});
useEffect(() => {
const unsubscribe = globalStore.subscribe(atomKey, () => {
const atom = globalStore.getAtom<T>(atomKey);
if (atom) {
setSelectedState(selector(atom.value));
}
});
return unsubscribe;
}, [atomKey, ...deps]);
return selectedState;
}
第三部分:高级特性实现
3.1 持久化支持
让我们添加状态持久化功能,将状态保存到localStorage。
// persistence.ts
export function withPersistence<T>(
atomKey: string,
storageKey: string,
storage: Storage = localStorage
) {
// 从存储中恢复状态
const saved = storage.getItem(storageKey);
let initialValue: T;
if (saved) {
try {
initialValue = JSON.parse(saved);
} catch {
initialValue = null as any;
}
}
// 创建原子
const atom = createAtom<T>(initialValue as T, atomKey);
// 订阅变化并保存到存储
globalStore.subscribe(atomKey, () => {
const atom = globalStore.getAtom<T>(atomKey);
if (atom) {
storage.setItem(storageKey, JSON.stringify(atom.value));
}
});
return atom;
}
// 使用示例
export function createPersistentAtom<T>(
initialValue: T,
storageKey: string
) {
return withPersistence<T>(
`persistent_${storageKey}`,
storageKey,
localStorage
);
}
3.2 中间件系统
中间件可以让我们在状态更新前后执行自定义逻辑。
// middleware.ts
export type Middleware<T> = (
atomKey: string,
nextValue: T,
prevValue: T
) => T | void;
export class MiddlewareManager {
private middlewares: Map<string, Middleware<any>[]> = new Map();
// 注册中间件
register<T>(atomKey: string, middleware: Middleware<T>) {
if (!this.middlewares.has(atomKey)) {
this.middlewares.set(atomKey, []);
}
this.middlewares.get(atomKey)!.push(middleware);
}
// 执行中间件链
execute<T>(atomKey: string, nextValue: T, prevValue: T): T {
const middlewares = this.middlewares.get(atomKey) || [];
let result = nextValue;
for (const middleware of middlewares) {
const middlewareResult = middleware(atomKey, result, prevValue);
if (middlewareResult !== undefined) {
result = middlewareResult;
}
}
return result;
}
}
// 日志中间件示例
export const loggerMiddleware: Middleware<any> = (
atomKey,
nextValue,
prevValue
) => {
console.log(`[${atomKey}]`, {
previous: prevValue,
next: nextValue,
timestamp: new Date().toISOString()