Appearance
状态管理方案选型 - 全面对比主流方案
1. 状态管理方案概览
1.1 主流方案
typescript
const stateManagementSolutions = {
内置方案: {
useState: '组件本地状态',
useReducer: '复杂本地状态',
Context: '跨组件共享',
特点: '无需额外依赖'
},
Redux生态: {
Redux: '经典方案',
ReduxToolkit: 'Redux官方推荐',
特点: '可预测、中间件丰富'
},
原子化方案: {
Recoil: 'Facebook出品',
Jotai: '轻量级原子状态',
特点: '细粒度订阅'
},
响应式方案: {
MobX: '响应式状态',
Valtio: '代理状态',
特点: '自动追踪依赖'
},
轻量方案: {
Zustand: '极简状态管理',
Valtio: '代理状态',
特点: 'API简单、包体积小'
}
};1.2 选型矩阵
typescript
const selectionMatrix = {
应用规模: {
小型: 'useState + Context',
中型: 'Zustand / Jotai',
大型: 'Redux Toolkit / MobX'
},
状态复杂度: {
简单: 'useState',
中等: 'useReducer / Zustand',
复杂: 'Redux / MobX'
},
团队经验: {
新手: 'useState + Context',
中级: 'Zustand / Jotai',
高级: 'Redux / MobX'
},
性能要求: {
一般: 'Context',
较高: 'Zustand / Jotai',
很高: 'Redux + Reselect'
}
};2. 方案详细对比
2.1 Redux Toolkit
typescript
const reduxToolkit = {
优势: [
'官方推荐',
'简化Redux使用',
'内置Immer',
'优秀的DevTools',
'强大的中间件'
],
示例: `
import { createSlice, configureStore } from '@reduxjs/toolkit';
const counterSlice = createSlice({
name: 'counter',
initialState: { value: 0 },
reducers: {
increment: state => { state.value += 1; },
decrement: state => { state.value -= 1; }
}
});
const store = configureStore({
reducer: { counter: counterSlice.reducer }
});
// 使用
const count = useSelector(state => state.counter.value);
const dispatch = useDispatch();
dispatch(counterSlice.actions.increment());
`,
适用场景: [
'大型应用',
'复杂状态逻辑',
'需要时间旅行调试',
'团队协作'
]
};2.2 Zustand
typescript
const zustand = {
优势: [
'API极简',
'包体积小(1KB)',
'无需Provider',
'TypeScript友好',
'性能优秀'
],
示例: `
import create from 'zustand';
const useStore = create((set) => ({
count: 0,
increment: () => set(state => ({ count: state.count + 1 })),
decrement: () => set(state => ({ count: state.count - 1 }))
}));
// 使用
function Counter() {
const count = useStore(state => state.count);
const increment = useStore(state => state.increment);
return <button onClick={increment}>{count}</button>;
}
`,
适用场景: [
'中小型应用',
'快速开发',
'简单状态逻辑',
'不需要复杂调试'
]
};2.3 Jotai
typescript
const jotai = {
优势: [
'原子化状态',
'细粒度更新',
'最小重渲染',
'TypeScript优秀',
'支持异步'
],
示例: `
import { atom, useAtom } from 'jotai';
const countAtom = atom(0);
const doubleAtom = atom(get => get(countAtom) * 2);
function Counter() {
const [count, setCount] = useAtom(countAtom);
const [double] = useAtom(doubleAtom);
return (
<div>
<p>Count: {count}</p>
<p>Double: {double}</p>
<button onClick={() => setCount(c => c + 1)}>+</button>
</div>
);
}
`,
适用场景: [
'需要细粒度更新',
'派生状态较多',
'中小型应用',
'性能敏感'
]
};2.4 MobX
typescript
const mobx = {
优势: [
'响应式编程',
'自动追踪依赖',
'简单的API',
'优秀的性能'
],
示例: `
import { makeAutoObservable } from 'mobx';
import { observer } from 'mobx-react-lite';
class CounterStore {
count = 0;
constructor() {
makeAutoObservable(this);
}
increment() {
this.count++;
}
get double() {
return this.count * 2;
}
}
const counterStore = new CounterStore();
const Counter = observer(() => {
return (
<div>
<p>{counterStore.count}</p>
<p>{counterStore.double}</p>
<button onClick={() => counterStore.increment()}>+</button>
</div>
);
});
`,
适用场景: [
'熟悉OOP',
'复杂派生状态',
'大型应用',
'需要自动追踪'
]
};4. 实战选型
4.1 项目类型选择
typescript
const projectTypeSelection = {
个人项目: 'useState + Context或Zustand',
中小型商业: 'Zustand或Jotai',
大型企业: 'Redux Toolkit',
高性能需求: 'Jotai或MobX',
快速原型: 'Zustand',
团队协作: 'Redux Toolkit (标准化)',
示例决策树: `
是否需要时间旅行调试?
是 -> Redux Toolkit
否 -> 继续
是否是大型应用?
是 -> Redux Toolkit / MobX
否 -> 继续
团队是否熟悉Redux?
是 -> Redux Toolkit
否 -> 继续
是否需要细粒度更新?
是 -> Jotai / MobX
否 -> Zustand
`
};5. 面试高频问题
typescript
const interviewQA = {
Q1: {
question: '如何选择状态管理方案?',
answer: [
'1. 考虑应用规模',
'2. 评估状态复杂度',
'3. 考虑团队经验',
'4. 性能要求',
'5. 调试需求',
'6. 生态系统'
]
},
Q2: {
question: '各方案的性能对比?',
answer: `
精确订阅: Redux > Jotai > Zustand > Context
包大小: Zustand < Jotai < Redux Toolkit
学习曲线: useState < Zustand < Jotai < Redux
`
}
};6. 总结
状态管理方案选型的核心要点:
- 内置方案: 适合简单场景
- Redux: 大型应用首选
- Zustand: 中小型应用最佳
- Jotai: 细粒度更新优秀
- MobX: 响应式编程
- 选型: 根据项目特点选择
没有最好的方案,只有最合适的方案。
7. Valtio深入解析
7.1 Valtio核心概念
javascript
import { proxy, useSnapshot } from 'valtio';
const state = proxy({
count: 0,
user: { name: 'John', age: 30 },
todos: []
});
function increment() {
state.count++;
}
function Counter() {
const snap = useSnapshot(state);
return <button onClick={increment}>{snap.count}</button>;
}7.2 Valtio优劣势
typescript
const valtioComparison = {
优势: ['极简API', '自动追踪', '直接修改', 'TypeScript友好', '体积小1KB'],
劣势: ['Proxy兼容性', '调试工具少', '生态较小'],
适用: ['中小型应用', '简单状态管理', 'Vue风格团队']
};8. Recoil深入解析
8.1 Recoil核心概念
javascript
import { atom, selector, useRecoilState, useRecoilValue } from 'recoil';
const textState = atom({
key: 'textState',
default: ''
});
const charCountState = selector({
key: 'charCountState',
get: ({ get }) => {
const text = get(textState);
return text.length;
}
});
const userInfoQuery = selector({
key: 'userInfoQuery',
get: async ({ get }) => {
const userId = get(currentUserIdState);
const response = await fetch(`/api/users/${userId}`);
return response.json();
}
});
const todoItemState = atomFamily({
key: 'todoItemState',
default: (id) => ({ id, text: '', completed: false })
});8.2 Recoil优劣势
typescript
const recoilComparison = {
优势: ['细粒度更新', '原生异步支持', 'Concurrent Mode集成', 'Atom清晰', '代码分割'],
劣势: ['实验性项目', 'API可能变化', '学习曲线陡', '调试工具有限'],
适用: ['细粒度状态', '大量派生状态', '异步管理', 'Concurrent项目']
};9. XState深入解析
9.1 XState核心概念
javascript
import { createMachine, interpret, assign } from 'xstate';
import { useMachine } from '@xstate/react';
const authMachine = createMachine({
id: 'auth',
initial: 'idle',
context: { user: null, error: null },
states: {
idle: { on: { LOGIN: 'loading' } },
loading: {
invoke: {
id: 'loginService',
src: (context, event) => loginUser(event.credentials),
onDone: { target: 'authenticated', actions: assign({ user: (_, event) => event.data }) },
onError: { target: 'error', actions: assign({ error: (_, event) => event.data }) }
}
},
authenticated: { on: { LOGOUT: 'idle' } },
error: { on: { RETRY: 'loading' } }
}
});
function AuthComponent() {
const [state, send] = useMachine(authMachine);
if (state.matches('idle')) return <button onClick={() => send({ type: 'LOGIN', credentials: {} })}>Login</button>;
if (state.matches('loading')) return <Loading />;
if (state.matches('authenticated')) return <div>Welcome, {state.context.user.name}! <button onClick={() => send('LOGOUT')}>Logout</button></div>;
if (state.matches('error')) return <div>Error: {state.context.error.message} <button onClick={() => send('RETRY')}>Retry</button></div>;
}9.2 XState优劣势
typescript
const xstateComparison = {
优势: ['状态可视化', '避免非法状态', '复杂逻辑清晰', '测试友好', '状态图生成'],
劣势: ['学习曲线陡', '样板代码多', '简单场景过度设计', '包体积大'],
适用: ['复杂状态转换', '工作流管理', '多步骤表单', '需要可视化']
};10. 选型决策树
10.1 选型流程
typescript
const decisionTree = {
项目规模: {
小型: { 推荐: ['useState', 'Context'], 原因: '简单直接' },
中型: { 推荐: ['Zustand', 'Jotai', 'Valtio'], 原因: '轻量完整' },
大型: { 推荐: ['Redux Toolkit', 'MobX'], 原因: '生态成熟' }
},
团队背景: {
熟悉Redux: { 推荐: 'Redux Toolkit', 原因: '降低学习成本' },
熟悉Vue: { 推荐: ['Valtio', 'MobX'], 原因: '响应式相似' },
新手: { 推荐: ['Zustand', 'Context'], 原因: 'API简单' }
},
性能要求: {
高频更新: { 推荐: ['Jotai', 'Recoil', 'Zustand'], 原因: '细粒度更新' },
一般: { 推荐: ['Redux Toolkit', 'Context'], 原因: '平衡性能开发' }
},
特殊需求: {
时间旅行: { 推荐: 'Redux Toolkit', 原因: 'DevTools' },
状态机: { 推荐: 'XState', 原因: '专为状态机设计' },
服务端状态: { 推荐: ['React Query', 'SWR', 'RTK Query'], 原因: '数据获取优化' }
}
};10.2 实际案例
typescript
const realCases = [
{ 项目: '电商平台', 规模: '大型', 选择: 'Redux Toolkit + RTK Query', 原因: ['复杂状态', '调试工具', '团队熟悉', 'API请求'] },
{ 项目: 'Todo应用', 规模: '小型', 选择: 'Context + useReducer', 原因: ['状态简单', '无需依赖', '学习成本低'] },
{ 项目: '数据看板', 规模: '中型', 选择: 'Zustand + React Query', 原因: ['UI状态', '服务端数据', '高频更新', 'API简单'] },
{ 项目: '协作编辑', 规模: '大型', 选择: 'Yjs + Zustand', 原因: ['协作同步', 'UI状态', '实时需求'] },
{ 项目: '表单流程', 规模: '中型', 选择: 'XState + React Hook Form', 原因: ['复杂流程', '多步骤', '状态清晰', '表单验证'] }
];11. 混合使用策略
11.1 分层状态管理
jsx
import { useQuery, useMutation } from '@tanstack/react-query';
import create from 'zustand';
function UserList() {
const { data: users } = useQuery({ queryKey: ['users'], queryFn: fetchUsers });
return <div>{/* 展示用户 */}</div>;
}
const useUIStore = create((set) => ({
sidebarOpen: false,
theme: 'light',
toggleSidebar: () => set(state => ({ sidebarOpen: !state.sidebarOpen })),
setTheme: (theme) => set({ theme })
}));
function App() {
const { sidebarOpen, toggleSidebar } = useUIStore();
return <div><button onClick={toggleSidebar}>Toggle</button>{sidebarOpen && <Sidebar />}</div>;
}
const cartSlice = createSlice({
name: 'cart',
initialState: { items: [] },
reducers: { addItem: (state, action) => { state.items.push(action.payload); } }
});
import { useForm } from 'react-hook-form';
function LoginForm() {
const { register, handleSubmit } = useForm();
const onSubmit = (data) => {};
return <form onSubmit={handleSubmit(onSubmit)}><input {...register('email')} /><button>Login</button></form>;
}11.2 混合策略
typescript
const hybridStrategy = {
服务端状态: { 工具: ['React Query', 'SWR', 'RTK Query'], 负责: ['数据获取', '缓存', '重试', '轮询'] },
UI状态: { 工具: ['Zustand', 'Jotai', 'Context'], 负责: ['主题', '侧边栏', '模态框', '输入'] },
全局业务: { 工具: ['Redux Toolkit', 'MobX'], 负责: ['用户', '购物车', '通知'] },
表单: { 工具: ['React Hook Form', 'Formik'], 负责: ['验证', '字段管理'] },
路由: { 工具: ['React Router', 'Next.js'], 负责: ['导航', '参数'] }
};12. 性能对比
12.1 渲染次数
typescript
const performanceTest = {
Context: { renders: 100, time: '~500ms', reason: '全量通知' },
Redux: { renders: 10, time: '~100ms', reason: '精确订阅' },
Zustand: { renders: 10, time: '~90ms', reason: '精确订阅' },
Jotai: { renders: 10, time: '~85ms', reason: '原子化更新' },
MobX: { renders: 10, time: '~95ms', reason: '自动追踪' }
};12.2 Bundle大小
typescript
const bundleSize = {
React内置: { useState: '0KB', useReducer: '0KB', Context: '0KB' },
轻量: { Zustand: '~1.1KB', Jotai: '~2.9KB', Valtio: '~1.2KB' },
中量: { 'React Query': '~13KB', XState: '~17KB' },
重量: { 'Redux Toolkit': '~48KB', MobX: '~19KB', Recoil: '~21KB' }
};13. 迁移指南
13.1 Redux到Zustand
javascript
// Redux
const initialState = { count: 0 };
function counterReducer(state = initialState, action) {
switch (action.type) {
case 'INCREMENT': return { ...state, count: state.count + 1 };
default: return state;
}
}
const store = createStore(counterReducer);
function Counter() {
const count = useSelector(state => state.count);
const dispatch = useDispatch();
return <button onClick={() => dispatch({ type: 'INCREMENT' })}>{count}</button>;
}
// Zustand
const useCounterStore = create((set) => ({
count: 0,
increment: () => set(state => ({ count: state.count + 1 }))
}));
function Counter() {
const { count, increment } = useCounterStore();
return <button onClick={increment}>{count}</button>;
}13.2 Context到Jotai
jsx
// Context
const CountContext = createContext();
function CountProvider({ children }) {
const [count, setCount] = useState(0);
return <CountContext.Provider value={{ count, setCount }}>{children}</CountContext.Provider>;
}
function Counter() {
const { count, setCount } = useContext(CountContext);
return <button onClick={() => setCount(c => c + 1)}>{count}</button>;
}
// Jotai
import { atom, useAtom } from 'jotai';
const countAtom = atom(0);
function Counter() {
const [count, setCount] = useAtom(countAtom);
return <button onClick={() => setCount(c => c + 1)}>{count}</button>;
}14. 面试重点
14.1 高频面试题
typescript
const questions = [
{ q: '如何选择状态管理方案?', a: '考虑:项目规模、团队背景、性能要求、特殊需求、学习成本' },
{ q: '5种方案特点?', a: 'Context简单内置、Redux功能强大、Zustand轻量简洁、Jotai原子化、MobX响应式' },
{ q: 'Zustand vs Redux场景?', a: 'Zustand适合中小型、不需复杂中间件、追求简洁API、团队经验少、不需时间旅行' },
{ q: '如何混合使用?', a: '分层:React Query服务端、Zustand全局业务、Context配置、Hook Form表单、useState局部UI' },
{ q: 'Jotai vs Recoil区别?', a: '相同:原子化、派生状态。不同:Jotai更轻量2.9KB vs 21KB、API更简单、Recoil实验性' }
];14.2 最佳实践
typescript
const practices = {
通用: ['优先React内置', '服务端状态用专门库', '避免过度设计', '考虑团队栈', '性能非首要'],
小型: ['Context + useReducer', '或Zustand', '避免Redux'],
中型: ['Zustand + React Query', '或Jotai + React Query'],
大型: ['Redux Toolkit + RTK Query', '或MobX + React Query', '需要调试工具'],
特殊: ['状态机用XState', '协作用Yjs', '表单用Hook Form']
};15. 状态管理演进
15.1 历史演进
typescript
const evolution = {
'2013-2015': { 方案: 'Flux', 特点: '单向数据流概念' },
'2015-2018': { 方案: 'Redux', 特点: '统一标准,生态繁荣' },
'2018-2020': { 方案: 'Context + Hooks', 特点: 'React内置方案成熟' },
'2020-2022': { 方案: 'Zustand/Jotai/Recoil', 特点: '轻量化、原子化' },
'2022-现在': { 方案: 'React Query/SWR', 特点: '服务端状态专门化' },
'未来': { 方案: 'React Forget', 特点: '自动优化,减少状态管理' }
};15.2 趋势分析
typescript
const trends = {
轻量化: '从Redux 48KB到Zustand 1KB',
原子化: 'Jotai/Recoil细粒度状态',
专门化: 'React Query处理服务端,Zustand处理UI',
自动化: 'React Compiler自动优化,减少手动管理',
类型化: 'TypeScript集成越来越好'
};16. 企业级实践
16.1 大型项目架构
typescript
const enterpriseArchitecture = {
层次: {
'1. 服务端状态层': 'RTK Query统一API管理',
'2. 全局业务层': 'Redux Toolkit核心业务逻辑',
'3. UI状态层': 'Zustand管理UI交互',
'4. 表单层': 'React Hook Form验证',
'5. 路由层': 'React Router导航'
},
规范: ['统一Store结构', 'Action命名规范', 'Selector模式', '错误处理', '日志系统'],
工具: ['Redux DevTools', 'React Query DevTools', 'Sentry监控', 'CI/CD集成']
};16.2 团队协作
typescript
const teamwork = {
代码规范: ['统一状态管理方案', 'Slice命名规范', 'Action类型规范', 'Selector复用'],
文档: ['状态流程图', 'API文档', '迁移指南', '最佳实践'],
培训: ['新人培训', '代码审查', '知识分享', '案例分析'],
工具: ['类型定义', 'ESLint规则', 'Git Hooks', 'CI检查']
};17. Pinia状态管理
17.1 Pinia概述
typescript
// Pinia是Vue 3官方状态管理库,但其思想可借鉴到React
const piniaFeatures = {
特点: [
'轻量级',
'TypeScript支持优秀',
'模块化设计',
'组合式API',
'插件系统'
],
对React的启示: [
'简洁的API设计',
'模块化状态管理',
'TypeScript优先',
'扁平化Store结构'
]
};
// React中类似Pinia的实现
import create from 'zustand';
const useUserStore = create((set, get) => ({
user: null,
token: null,
// Actions
setUser: (user) => set({ user }),
setToken: (token) => set({ token }),
// Getters
get isAuthenticated() {
return !!get().token;
},
get userName() {
return get().user?.name || 'Guest';
}
}));17.2 Pinia风格在React中的应用
typescript
// 借鉴Pinia的设计理念创建React Store
interface UserState {
user: User | null;
loading: boolean;
error: string | null;
}
interface UserActions {
fetchUser: (id: string) => Promise<void>;
updateUser: (data: Partial<User>) => void;
logout: () => void;
}
interface UserGetters {
isAuthenticated: boolean;
fullName: string;
}
type UserStore = UserState & UserActions & UserGetters;
const useUserStore = create<UserStore>((set, get) => ({
// State
user: null,
loading: false,
error: null,
// Actions
fetchUser: async (id) => {
set({ loading: true, error: null });
try {
const user = await fetchUserAPI(id);
set({ user, loading: false });
} catch (error) {
set({ error: error.message, loading: false });
}
},
updateUser: (data) => {
set(state => ({
user: state.user ? { ...state.user, ...data } : null
}));
},
logout: () => {
set({ user: null, token: null });
},
// Getters
get isAuthenticated() {
return !!get().user;
},
get fullName() {
const user = get().user;
return user ? `${user.firstName} ${user.lastName}` : '';
}
}));18. Immer深入应用
18.1 Immer在状态管理中的应用
typescript
// Immer简化不可变数据更新
import produce from 'immer';
import create from 'zustand';
interface TodoState {
todos: Todo[];
}
const useTodoStore = create<TodoState>((set) => ({
todos: [],
// 不使用Immer
addTodoWithoutImmer: (todo) => set(state => ({
todos: [...state.todos, todo]
})),
// 使用Immer
addTodo: (todo) => set(
produce((draft) => {
draft.todos.push(todo);
})
),
// 复杂嵌套更新
updateTodoTag: (todoId, tagIndex, newTag) => set(
produce((draft) => {
const todo = draft.todos.find(t => t.id === todoId);
if (todo) {
todo.tags[tagIndex] = newTag;
}
})
)
}));18.2 Immer最佳实践
typescript
const immerBestPractices = {
适用场景: [
'深层嵌套数据结构',
'数组操作(push/splice)',
'复杂对象更新',
'多处数据修改'
],
不适用场景: [
'简单浅层更新',
'性能极致要求',
'大量数据批量更新'
],
性能优化: [
'避免在循环中使用produce',
'批量更新合并为一次produce',
'使用freeze减少produce次数'
]
};
// 示例
const useOptimizedStore = create((set) => ({
items: [],
// 不好的做法
updateItemsBad: (updates) => {
updates.forEach(update => {
set(produce(draft => {
const item = draft.items.find(i => i.id === update.id);
if (item) Object.assign(item, update.data);
}));
});
},
// 好的做法
updateItemsGood: (updates) => {
set(produce(draft => {
updates.forEach(update => {
const item = draft.items.find(i => i.id === update.id);
if (item) Object.assign(item, update.data);
});
}));
}
}));19. 状态持久化方案
19.1 LocalStorage持久化
typescript
// Zustand持久化中间件
import create from 'zustand';
import { persist, createJSONStorage } from 'zustand/middleware';
const useStore = create(
persist(
(set, get) => ({
user: null,
settings: {
theme: 'light',
language: 'zh-CN'
},
setUser: (user) => set({ user }),
updateSettings: (settings) => set(state => ({
settings: { ...state.settings, ...settings }
}))
}),
{
name: 'app-storage',
storage: createJSONStorage(() => localStorage),
// 选择性持久化
partialize: (state) => ({
user: state.user,
settings: state.settings
})
}
)
);
// Redux持久化
import { configureStore } from '@reduxjs/toolkit';
import {
persistStore,
persistReducer,
FLUSH,
REHYDRATE,
PAUSE,
PERSIST,
PURGE,
REGISTER
} from 'redux-persist';
import storage from 'redux-persist/lib/storage';
const persistConfig = {
key: 'root',
version: 1,
storage,
whitelist: ['user', 'settings']
};
const persistedReducer = persistReducer(persistConfig, rootReducer);
const store = configureStore({
reducer: persistedReducer,
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({
serializableCheck: {
ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER]
}
})
});
export const persistor = persistStore(store);19.2 IndexedDB持久化
typescript
// 使用IndexedDB进行大数据量持久化
import create from 'zustand';
import { persist } from 'zustand/middleware';
// 自定义IndexedDB Storage
const createIndexedDBStorage = () => {
const dbName = 'app-db';
const storeName = 'app-store';
let db: IDBDatabase;
const initDB = () => new Promise<IDBDatabase>((resolve, reject) => {
const request = indexedDB.open(dbName, 1);
request.onerror = () => reject(request.error);
request.onsuccess = () => resolve(request.result);
request.onupgradeneeded = (event) => {
const db = (event.target as IDBOpenDBRequest).result;
if (!db.objectStoreNames.contains(storeName)) {
db.createObjectStore(storeName);
}
};
});
return {
getItem: async (key: string) => {
if (!db) db = await initDB();
return new Promise((resolve, reject) => {
const transaction = db.transaction(storeName, 'readonly');
const store = transaction.objectStore(storeName);
const request = store.get(key);
request.onerror = () => reject(request.error);
request.onsuccess = () => resolve(request.result);
});
},
setItem: async (key: string, value: any) => {
if (!db) db = await initDB();
return new Promise((resolve, reject) => {
const transaction = db.transaction(storeName, 'readwrite');
const store = transaction.objectStore(storeName);
const request = store.put(value, key);
request.onerror = () => reject(request.error);
request.onsuccess = () => resolve();
});
},
removeItem: async (key: string) => {
if (!db) db = await initDB();
return new Promise((resolve, reject) => {
const transaction = db.transaction(storeName, 'readwrite');
const store = transaction.objectStore(storeName);
const request = store.delete(key);
request.onerror = () => reject(request.error);
request.onsuccess = () => resolve();
});
}
};
};
// 使用IndexedDB Storage
const useDataStore = create(
persist(
(set) => ({
largeDataset: [],
setLargeDataset: (data) => set({ largeDataset: data })
}),
{
name: 'large-data',
storage: createIndexedDBStorage()
}
)
);20. 状态同步策略
20.1 多Tab同步
typescript
// 使用BroadcastChannel实现多Tab状态同步
import create from 'zustand';
const createSyncedStore = (name: string, initialState: any) => {
const channel = new BroadcastChannel(name);
const store = create((set, get) => ({
...initialState,
_sync: (state: any) => {
set(state);
channel.postMessage({ type: 'STATE_UPDATE', state });
}
}));
channel.addEventListener('message', (event) => {
if (event.data.type === 'STATE_UPDATE') {
store.setState(event.data.state);
}
});
return store;
};
// 使用
const useUserStore = createSyncedStore('user-store', {
user: null,
setUser: (user) => useUserStore.getState()._sync({ user })
});20.2 服务端状态同步
typescript
// 使用WebSocket实现实时状态同步
import create from 'zustand';
import io from 'socket.io-client';
const useRealtimeStore = create((set, get) => {
const socket = io('ws://localhost:3000');
socket.on('state-update', (update) => {
set(update);
});
return {
messages: [],
onlineUsers: [],
addMessage: (message) => {
set(state => ({
messages: [...state.messages, message]
}));
socket.emit('message', message);
},
updateOnlineUsers: (users) => {
set({ onlineUsers: users });
}
};
});21. 状态调试工具
21.1 Redux DevTools集成
typescript
// Zustand集成Redux DevTools
import create from 'zustand';
import { devtools } from 'zustand/middleware';
const useStore = create(
devtools(
(set) => ({
count: 0,
increment: () => set(
(state) => ({ count: state.count + 1 }),
false,
'increment'
),
decrement: () => set(
(state) => ({ count: state.count - 1 }),
false,
'decrement'
)
}),
{
name: 'CounterStore',
enabled: process.env.NODE_ENV === 'development'
}
)
);
// Jotai DevTools
import { useAtom } from 'jotai';
import { useAtomDevtools } from 'jotai/devtools';
function Counter() {
const [count, setCount] = useAtom(countAtom);
useAtomDevtools(countAtom, 'count');
return (
<div>
<p>{count}</p>
<button onClick={() => setCount(c => c + 1)}>+</button>
</div>
);
}21.2 自定义调试工具
typescript
// 创建状态变化日志中间件
const logger = (config) => (set, get, api) => {
return config((args) => {
const prevState = get();
set(args);
const nextState = get();
console.group('State Change');
console.log('Previous:', prevState);
console.log('Action:', args);
console.log('Next:', nextState);
console.groupEnd();
}, get, api);
};
const useStore = create(
logger((set) => ({
count: 0,
increment: () => set(state => ({ count: state.count + 1 }))
}))
);
// 时间旅行调试
const timeTravelMiddleware = (config) => (set, get, api) => {
const history = [];
let currentIndex = -1;
const wrappedSet = (args) => {
set(args);
const state = get();
history.push(state);
currentIndex++;
};
return {
...config(wrappedSet, get, api),
undo: () => {
if (currentIndex > 0) {
currentIndex--;
set(history[currentIndex]);
}
},
redo: () => {
if (currentIndex < history.length - 1) {
currentIndex++;
set(history[currentIndex]);
}
},
canUndo: () => currentIndex > 0,
canRedo: () => currentIndex < history.length - 1
};
};22. 状态测试策略
22.1 Redux测试
typescript
// Redux Slice测试
import { configureStore } from '@reduxjs/toolkit';
import counterReducer, { increment, decrement } from './counterSlice';
describe('Counter Slice', () => {
let store;
beforeEach(() => {
store = configureStore({
reducer: { counter: counterReducer }
});
});
test('should handle initial state', () => {
expect(store.getState().counter.value).toBe(0);
});
test('should handle increment', () => {
store.dispatch(increment());
expect(store.getState().counter.value).toBe(1);
});
test('should handle decrement', () => {
store.dispatch(decrement());
expect(store.getState().counter.value).toBe(-1);
});
});
// 异步Action测试
import { fetchUser } from './userSlice';
test('should fetch user', async () => {
const mockUser = { id: 1, name: 'John' };
global.fetch = jest.fn(() =>
Promise.resolve({
json: () => Promise.resolve(mockUser)
})
);
await store.dispatch(fetchUser(1));
const state = store.getState();
expect(state.user.data).toEqual(mockUser);
expect(state.user.loading).toBe(false);
});22.2 Zustand测试
typescript
// Zustand Store测试
import { renderHook, act } from '@testing-library/react';
import { useStore } from './store';
describe('Zustand Store', () => {
test('should increment count', () => {
const { result } = renderHook(() => useStore());
act(() => {
result.current.increment();
});
expect(result.current.count).toBe(1);
});
test('should reset count', () => {
const { result } = renderHook(() => useStore());
act(() => {
result.current.increment();
result.current.increment();
result.current.reset();
});
expect(result.current.count).toBe(0);
});
});
// 持久化测试
import { persist } from 'zustand/middleware';
test('should persist state', () => {
const usePersistedStore = create(
persist(
(set) => ({
count: 0,
increment: () => set(state => ({ count: state.count + 1 }))
}),
{
name: 'test-storage',
storage: {
getItem: jest.fn(),
setItem: jest.fn(),
removeItem: jest.fn()
}
}
)
);
const { result } = renderHook(() => usePersistedStore());
act(() => {
result.current.increment();
});
expect(result.current.count).toBe(1);
});22.3 React Query测试
typescript
// React Query测试
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { renderHook, waitFor } from '@testing-library/react';
import { useUsers } from './hooks';
describe('useUsers', () => {
let queryClient;
beforeEach(() => {
queryClient = new QueryClient({
defaultOptions: {
queries: { retry: false }
}
});
});
const wrapper = ({ children }) => (
<QueryClientProvider client={queryClient}>
{children}
</QueryClientProvider>
);
test('should fetch users', async () => {
const mockUsers = [{ id: 1, name: 'John' }];
global.fetch = jest.fn(() =>
Promise.resolve({
json: () => Promise.resolve(mockUsers)
})
);
const { result } = renderHook(() => useUsers(), { wrapper });
await waitFor(() => expect(result.current.isSuccess).toBe(true));
expect(result.current.data).toEqual(mockUsers);
});
test('should handle error', async () => {
global.fetch = jest.fn(() =>
Promise.reject(new Error('Network error'))
);
const { result } = renderHook(() => useUsers(), { wrapper });
await waitFor(() => expect(result.current.isError).toBe(true));
expect(result.current.error).toBeDefined();
});
});23. 状态安全实践
23.1 防止XSS攻击
typescript
// 状态数据清理和验证
import DOMPurify from 'dompurify';
const useSafeStore = create((set) => ({
content: '',
setContent: (rawContent) => {
// 清理HTML内容
const cleanContent = DOMPurify.sanitize(rawContent);
set({ content: cleanContent });
}
}));
// 输入验证
const validateInput = (input: string): boolean => {
// 检查SQL注入
const sqlPattern = /(\bor\b|\band\b|union|select|insert|update|delete|drop)/i;
if (sqlPattern.test(input)) return false;
// 检查XSS
const xssPattern = /<script|javascript:|onerror=/i;
if (xssPattern.test(input)) return false;
return true;
};
const useSecureStore = create((set) => ({
userInput: '',
setUserInput: (input) => {
if (validateInput(input)) {
set({ userInput: input });
} else {
console.error('Invalid input detected');
}
}
}));23.2 敏感数据处理
typescript
// 敏感数据加密存储
import CryptoJS from 'crypto-js';
const SECRET_KEY = process.env.REACT_APP_SECRET_KEY;
const encryptData = (data: any): string => {
return CryptoJS.AES.encrypt(
JSON.stringify(data),
SECRET_KEY
).toString();
};
const decryptData = (encrypted: string): any => {
const bytes = CryptoJS.AES.decrypt(encrypted, SECRET_KEY);
return JSON.parse(bytes.toString(CryptoJS.enc.Utf8));
};
// 加密持久化
const useSecurePersistedStore = create(
persist(
(set) => ({
sensitiveData: null,
setSensitiveData: (data) => set({ sensitiveData: data })
}),
{
name: 'secure-storage',
storage: {
getItem: (name) => {
const encrypted = localStorage.getItem(name);
return encrypted ? decryptData(encrypted) : null;
},
setItem: (name, value) => {
const encrypted = encryptData(value);
localStorage.setItem(name, encrypted);
},
removeItem: (name) => {
localStorage.removeItem(name);
}
}
}
)
);24. 状态性能监控
24.1 性能指标收集
typescript
// 状态更新性能监控
const createPerformanceMonitor = () => {
const metrics = [];
return {
measure: (name: string, fn: Function) => {
const start = performance.now();
const result = fn();
const end = performance.now();
metrics.push({
name,
duration: end - start,
timestamp: Date.now()
});
return result;
},
getMetrics: () => metrics,
getAverageDuration: (name: string) => {
const filtered = metrics.filter(m => m.name === name);
if (filtered.length === 0) return 0;
const sum = filtered.reduce((acc, m) => acc + m.duration, 0);
return sum / filtered.length;
}
};
};
const monitor = createPerformanceMonitor();
const useMonitoredStore = create((set) => ({
data: [],
updateData: (newData) => {
monitor.measure('updateData', () => {
set({ data: newData });
});
}
}));24.2 渲染性能追踪
typescript
// 追踪状态变化导致的渲染
import { useEffect, useRef } from 'react';
const useRenderCount = (componentName: string) => {
const renderCount = useRef(0);
useEffect(() => {
renderCount.current++;
console.log(`${componentName} rendered ${renderCount.current} times`);
});
return renderCount.current;
};
// 使用
function MyComponent() {
const renderCount = useRenderCount('MyComponent');
const data = useStore(state => state.data);
return <div>Renders: {renderCount}</div>;
}
// 检测不必要的重渲染
const useWhyDidYouUpdate = (name: string, props: any) => {
const previousProps = useRef(props);
useEffect(() => {
if (previousProps.current) {
const allKeys = Object.keys({ ...previousProps.current, ...props });
const changedProps = {};
allKeys.forEach(key => {
if (previousProps.current[key] !== props[key]) {
changedProps[key] = {
from: previousProps.current[key],
to: props[key]
};
}
});
if (Object.keys(changedProps).length > 0) {
console.log('[why-did-you-update]', name, changedProps);
}
}
previousProps.current = props;
});
};25. 总结与展望
25.1 状态管理演进趋势
typescript
const trends = {
当前趋势: [
'轻量化: 从Redux到Zustand',
'原子化: Recoil/Jotai细粒度管理',
'服务端状态分离: React Query/SWR',
'TypeScript优先: 类型安全',
'自动优化: React Compiler'
],
未来方向: [
'更智能的自动优化',
'更好的开发者体验',
'更小的bundle大小',
'更强的类型推导',
'AI辅助状态管理'
],
选型建议: [
'小型项目: Context + useState',
'中型项目: Zustand/Jotai + React Query',
'大型项目: Redux Toolkit + RTK Query',
'特殊需求: XState(状态机) / Yjs(协作)'
]
};25.2 最终建议
typescript
const finalAdvice = {
通用原则: [
'优先使用React内置方案',
'服务端状态用专门的库',
'避免过度设计',
'根据团队技术栈选择',
'性能不是首要考虑'
],
学习路径: [
'1. 深入理解useState/useReducer',
'2. 掌握Context API',
'3. 学习一个轻量方案(Zustand)',
'4. 了解Redux Toolkit',
'5. 掌握React Query',
'6. 根据需求探索其他方案'
],
实战经验: [
'从简单开始,逐步优化',
'监控性能指标',
'建立团队规范',
'做好文档和培训',
'持续重构和改进'
]
};25.3 状态管理核心要点
- 没有银弹: 没有完美的方案,只有最适合的方案
- 分层管理: 服务端状态、全局状态、局部状态分离
- 性能优化: 精确订阅、选择器优化、批量更新
- 开发体验: TypeScript支持、DevTools、调试工具
- 团队协作: 统一规范、文档完善、培训到位
- 持续演进: 关注新技术、适时重构、保持学习
状态管理是React应用的核心,选择合适的方案并正确使用,是构建高质量应用的关键。