引言
在现代前端开发中,状态管理一直是构建复杂应用的核心挑战。随着 React Hooks 的普及,开发者有了更多轻量级的状态管理选择。本文将带你从零实现一个轻量级的 React 状态管理库,深入探讨其设计思路、实现细节和最佳实践。
为什么需要另一个状态管理库?
Redux、MobX、Zustand 等成熟方案已经非常优秀,但在某些场景下,我们可能希望:
- 更小的包体积(< 2KB)
- 更简单的 API 设计
- 更好的 TypeScript 支持
- 更灵活的状态更新策略
让我们开始构建一个名为 MicroState 的轻量级状态管理库。
核心设计目标
我们的状态管理库将遵循以下设计原则:
- 极简 API:只需 3 个核心函数
- 零依赖:不依赖任何第三方库
- 完整的 TypeScript 支持
- 支持中间件扩展
- 高性能更新:避免不必要的重渲染
基础架构设计
1. 状态存储设计
首先,我们需要一个中心化的状态存储:
type Listener<T> = (state: T) => void;
type Unsubscribe = () => void;
class Store<T> {
private state: T;
private listeners: Set<Listener<T>> = new Set();
constructor(initialState: T) {
this.state = initialState;
}
getState(): T {
return this.state;
}
setState(updater: T | ((prevState: T) => T)) {
const nextState = typeof updater === 'function'
? (updater as (prev: T) => T)(this.state)
: updater;
if (nextState !== this.state) {
this.state = nextState;
this.notifyListeners();
}
}
subscribe(listener: Listener<T>): Unsubscribe {
this.listeners.add(listener);
return () => this.listeners.delete(listener);
}
private notifyListeners() {
this.listeners.forEach(listener => listener(this.state));
}
}
2. React 集成 Hook
为了让状态与 React 组件无缝集成,我们需要创建一个自定义 Hook:
import { useState, useEffect, useRef } from 'react';
export function createUseStore<T>(store: Store<T>) {
return function useStore<U = T>(
selector?: (state: T) => U
): U {
const [state, setState] = useState(() =>
selector ? selector(store.getState()) : store.getState()
);
const selectorRef = useRef(selector);
const stateRef = useRef(state);
useEffect(() => {
selectorRef.current = selector;
stateRef.current = state;
});
useEffect(() => {
const checkForUpdates = () => {
const nextState = selectorRef.current
? selectorRef.current(store.getState())
: store.getState();
if (nextState !== stateRef.current) {
setState(nextState);
}
};
const unsubscribe = store.subscribe(checkForUpdates);
return unsubscribe;
}, [store]);
return state;
};
}
3. 创建 Store 的工厂函数
export function createStore<T>(initialState: T) {
const store = new Store(initialState);
return {
getState: store.getState.bind(store),
setState: store.setState.bind(store),
subscribe: store.subscribe.bind(store),
useStore: createUseStore(store),
};
}
完整实现与类型安全
让我们将所有部分组合起来,并添加完整的 TypeScript 支持:
// micro-state.ts
export type StoreApi<T> = {
getState: () => T;
setState: (updater: T | ((prevState: T) => T)) => void;
subscribe: (listener: (state: T) => void) => () => void;
useStore: <U = T>(selector?: (state: T) => U) => U;
};
export function createStore<T>(initialState: T): StoreApi<T> {
type Listener = (state: T) => void;
let state = initialState;
const listeners = new Set<Listener>();
const getState = () => state;
const setState = (updater: T | ((prevState: T) => T)) => {
const nextState = typeof updater === 'function'
? (updater as (prev: T) => T)(state)
: updater;
if (!Object.is(nextState, state)) {
state = nextState;
listeners.forEach(listener => listener(state));
}
};
const subscribe = (listener: Listener) => {
listeners.add(listener);
return () => listeners.delete(listener);
};
const useStore = <U = T>(selector?: (state: T) => U): U => {
const [selectedState, setSelectedState] = React.useState(() =>
selector ? selector(state) : state
);
React.useEffect(() => {
const listener = () => {
const nextSelectedState = selector ? selector(state) : state;
if (!Object.is(nextSelectedState, selectedState)) {
setSelectedState(nextSelectedState);
}
};
const unsubscribe = subscribe(listener);
return unsubscribe;
}, [selector]);
return selectedState as U;
};
return {
getState,
setState,
subscribe,
useStore,
};
}
中间件系统
为了提供扩展能力,我们实现一个简单的中间件系统:
type Middleware<T> = (
store: StoreApi<T>
) => (next: (updater: T | ((prev: T) => T)) => void) =>
(updater: T | ((prev: T) => T)) => void;
export function applyMiddleware<T>(
store: StoreApi<T>,
middlewares: Middleware<T>[]
): StoreApi<T> {
let setState = store.setState;
// 从右到左组合中间件
const chain = middlewares.map(middleware => middleware(store));
chain.reverse().forEach(middleware => {
setState = middleware(setState);
});
return {
...store,
setState,
};
}
// 示例:日志中间件
export const loggerMiddleware: Middleware<any> = (store) => (next) => (updater) => {
console.group('State Update');
console.log('Previous State:', store.getState());
const result = next(updater);
console.log('Next State:', store.getState());
console.groupEnd();
return result;
};
// 示例:持久化中间件
export const persistMiddleware = <T>(key: string): Middleware<T> => (store) => (next) => (updater) => {
const result = next(updater);
// 保存到 localStorage
try {
localStorage.setItem(key, JSON.stringify(store.getState()));
} catch (error) {
console.warn('Failed to persist state:', error);
}
return result;
};
使用示例
让我们看看如何在真实项目中使用这个状态管理库:
// store/counterStore.ts
import { createStore, applyMiddleware, loggerMiddleware } from '../micro-state';
interface CounterState {
count: number;
loading: boolean;
}
const initialState: CounterState = {
count: 0,
loading: false,
};
// 创建基础 store
const baseStore = createStore(initialState);
// 应用中间件
export const counterStore = applyMiddleware(
baseStore,
[loggerMiddleware]
);
// 定义 actions
export const counterActions = {
increment: () => {
counterStore.setState(prev => ({
...prev,
count: prev.count + 1,
}));
},
decrement: () => {
counterStore.setState(prev => ({
...prev,
count: prev.count - 1,
}));
},
incrementAsync: async () => {
counterStore.setState(prev => ({ ...prev, loading: true }));
await new Promise(resolve => setTimeout(resolve, 1000));
counterStore.setState(prev => ({
...prev,
count: prev.count + 1,
loading: false,
}));
},
};
在组件中使用:
// components/Counter.tsx
import React from 'react';
import { counterStore, counterActions } from '../store/counterStore';
export const Counter: React.FC = () => {
// 使用完整状态
const { count, loading } = counterStore.useStore();
// 或者使用选择器获取部分状态
const countOnly = counterStore.useStore(state => state.count);
return (
<div className="counter">
<h2>Count: {count}</h2>
<div className="buttons">
<button
onClick