行业资讯
React状态管理方案迁移复盘:从Redux到Zustand的渐进式替换经验
React状态管理方案迁移复盘从Redux到Zustand的渐进式替换经验一、Redux的重在哪里一个React中后台项目使用Redux Toolkit管理全局状态。2年下来Redux代码膨胀到可用性问题12个slice文件平均每个200行Store初始化需要配置5个中间件thunk、logger、persist、devtools、immutability check新增一个状态字段需要修改5个文件slice、type、action、selector、component做一个下拉框的联动需要约60行Redux代码。问题的本质Redux给了我们一套严谨的状态管理方法论但95%的状态场景不需要这么严谨。迁移目标把Redux Store中的状态逐步迁移到Zustand保持类型安全保持中间件支持persist、devtools。二、迁移策略不是替换而是共存原则一新模块直接用Zustand不动旧代码。订单管理模块是新开发的直接从Zustand开始不与Redux交互。原则二旧Store按依赖少→依赖多的顺序迁移。UI Store主题、侧边栏不依赖任何其他Store最先迁移。Auth Store被多处引用最后迁移。// 迁移前Redux UI Slice —— 150行 // store/uiSlice.ts const uiSlice createSlice({ name: ui, initialState: { sidebarCollapsed: false, theme: light as light | dark, loading: false, }, reducers: { toggleSidebar(state) { state.sidebarCollapsed !state.sidebarCollapsed; }, setTheme(state, action: PayloadActionlight | dark) { state.theme action.payload; }, setLoading(state, action: PayloadActionboolean) { state.loading action.payload; }, }, }); // 迁移后Zustand Store —— 60行 // stores/useUIStore.ts import { create } from zustand; import { persist } from zustand/middleware; interface UIState { sidebarCollapsed: boolean; theme: light | dark; loading: boolean; toggleSidebar: () void; setTheme: (theme: light | dark) void; setLoading: (loading: boolean) void; } export const useUIStore createUIState()( persist( (set) ({ sidebarCollapsed: false, theme: light, loading: false, toggleSidebar: () set((state) ({ sidebarCollapsed: !state.sidebarCollapsed })), setTheme: (theme) set({ theme }), setLoading: (loading) set({ loading }), }), { name: ui-store } // localStorage持久化 ) );代码量从150行降到60行60%减少。不需要Provider包裹、不需要dispatch、不需要actionCreator。组件中使用的变化// Redux 方式 const dispatch useDispatch(); const sidebarCollapsed useSelector((state: RootState) state.ui.sidebarCollapsed); dispatch(toggleSidebar()); // Zustand 方式 const { sidebarCollapsed, toggleSidebar } useUIStore();三、中间件Zustand如何替代Redux中间件持久化persistZustand的persist中间件比redux-persist简单得多——不需要PersistGate组件。开发者工具devtools添加一行即可import { devtools } from zustand/middleware; export const useAuthStore createAuthState()( devtools( persist((set) ({...})), { name: auth-store } ) );不可变性检查immerimport { immer } from zustand/middleware/immer; export const useOrderStore createOrderState()( immer((set) ({ items: [], addItem: (item) set((state) { state.items.push(item); // 可以直接mutateimmer处理不可变性 }), })) );四、迁移中的坑坑1Redux和Zustand共存的DevTools混乱。当两者同时运行时Redux DevTools中只能看到Redux的action。解决方案给Zustand的devtools指定不同的name在DevTools的实例切换中查看。坑2中间件的执行顺序敏感。Zustand的中间件是从右到左执行的compose。devtools(persist(store))和persist(devtools(store))的行为不同。正确顺序devtools(persist(...))——先执行persist加载本地数据devtools在外部记录。坑3selector的性能差异。Redux的useSelector有内置的浅比较优化。Zustand的useStore(selector)默认使用Object.is需要手动提供shallow比较函数import { shallow } from zustand/shallow; // 不好——每次返回新引用导致重渲染 const { name, age } useUserStore(); // 好——用shallow比较 const { name, age } useUserStore( (state) ({ name: state.name, age: state.age }), shallow );五、总结从Redux到Zustand的核心体验Zustand的代码量平均是Redux的40-50%。不是因为Zustand更聪明而是因为Redux设计了很多非必须的抽象层。不需要Provider是最大的使用体验提升——少了顶层Provider的包裹少了测试环境的Store Mock。迁移一定不能大爆炸。Redux和Zustand可以共存按模块渐进迁移。中间件生态系统Zustand虽然不如Redux丰富但核心场景persist、devtools、immer都有官方支持。迁移完成后Redux Store从12个slice减少到1个权限管理保留Zustand Store新增7个。开发者新增一个状态管理单元的时间从约30分钟降到10分钟。最大的隐性收益是新成员不需要学习Redux的action/reducer/dispatch概念——直接看Zustand的StoreuseStore取值改值。学习成本降低约60%。
郑州网站建设
网页设计
企业官网