基于 React Hook 封裝 Store 的三種方案
方案一:基于 useSyncExternalStore
的輕量級 Store(推薦)
import { useSyncExternalStore } from 'react';type Store<T> = {state: T;listeners: Set<() => void>;
};function createStore<T>(initialState: T) {const store: Store<T> = {state: initialState,listeners: new Set(),};const setState = (updater: (prev: T) => T) => {store.state = updater(store.state);store.listeners.forEach(listener => listener());};const subscribe = (listener: () => void) => {store.listeners.add(listener);return () => store.listeners.delete(listener);};const useStore = <S>(selector: (state: T) => S): S => {return useSyncExternalStore(subscribe,() => selector(store.state),() => selector(initialState));};return [useStore, setState] as const;
}
特性:零依賴、無 Provider、精準渲染
方案二:基于 Context + useReducer
import { createContext, useContext, useReducer } from 'react';type State = { count: number };
type Action = { type: 'INCREMENT' } | { type: 'DECREMENT' };const StoreContext = createContext<{state: State;dispatch: React.Dispatch<Action>;
}>(null!);function StoreProvider({ children }) {const [state, dispatch] = useReducer((prev: State, action: Action) => {switch (action.type) {case 'INCREMENT': return { ...prev, count: prev.count + 1 };case 'DECREMENT': return { ...prev, count: prev.count - 1 };default: return prev;}},{ count: 0 });return (<StoreContext.Provider value={{ state, dispatch }}>{children}</StoreContext.Provider>);
}function useStore() {const { state, dispatch } = useContext(StoreContext);return {count: state.count,increment: () => dispatch({ type: 'INCREMENT' }),decrement: () => dispatch({ type: 'DECREMENT' })};
}
優勢:支持中間件、復雜狀態管理
方案三:基于閉包的輕量實現
import { useState, useMemo } from 'react';function createStore<T>(initialState: T) {let state = initialState;const listeners = new Set<() => void>();const setState = (updater: (prev: T) => T) => {state = updater(state);listeners.forEach(listener => listener());};function useStore(): [T, typeof setState] {const [, forceUpdate] = useState({});useMemo(() => {listeners.add(forceUpdate);return () => { listeners.delete(forceUpdate); };}, []);return [state, setState];}return useStore;
}
特點:<20行代碼實現
方案選型對比
方案 | 適用場景 | 優點 | 缺點 |
---|---|---|---|
useSyncExternalStore | 大型應用全局狀態 | 高性能、無 Provider 污染 | 需要 React 18+ |
Context + Reducer | 復雜業務流 | 支持中間件、類型安全 | 需要 Provider 包裹 |
閉包實現 | 小型應用/組件間共享 | 實現簡單、零依賴 | 無法跨組件樹隔離狀態 |