![]()
Context + useReducer 模式
一、为什么需要状态管理?
1.1 Props Drilling 问题
// ❌ 层层传递,繁琐且难以维护 <GrandParent user={user}> <Parent user={user}> <Child user={user}> <GrandChild user={user} /> </Child> </Parent> </GrandParent>
1.2 解决方案对比
| 方案 | 适用场景 | 优点 | 缺点 |
|---|
| Props | 简单父子组件 | 简单直接 | 层级深时繁琐 |
| Context | 跨层级传递 | 避免 props drilling | 过度使用影响性能 |
| Context + useReducer | 中等复杂度应用 | 轻量、内置 | 比 Zustand 代码多 |
| Zustand/Redux | 大型应用 | 功能强大 | 学习成本 |
二、Context + useReducer 基础
2.1 创建状态管理
// store/AppContext.js import React, { createContext, useContext, useReducer } from 'react'; // 1. 定义初始状态 const initialState = { user: null, theme: 'light', count: 0, notifications: [] }; // 2. 定义 Action 类型 const ACTIONS = { SET_USER: 'SET_USER', TOGGLE_THEME: 'TOGGLE_THEME', INCREMENT: 'INCREMENT', DECREMENT: 'DECREMENT', ADD_NOTIFICATION: 'ADD_NOTIFICATION', REMOVE_NOTIFICATION: 'REMOVE_NOTIFICATION' }; // 3. 定义 Reducer function appReducer(state, action) { switch (action.type) { case ACTIONS.SET_USER: return { ...state, user: action.payload }; case ACTIONS.TOGGLE_THEME: return { ...state, theme: state.theme === 'light' ? 'dark' : 'light' }; case ACTIONS.INCREMENT: return { ...state, count: state.count + 1 }; case ACTIONS.DECREMENT: return { ...state, count: state.count - 1 }; case ACTIONS.ADD_NOTIFICATION: return { ...state, notifications: [...state.notifications, action.payload] }; case ACTIONS.REMOVE_NOTIFICATION: return { ...state, notifications: state.notifications.filter(n => n.id !== action.payload) }; default: return state; } } // 4. 创建 Context const AppContext = createContext(); // 5. Provider 组件 export function AppProvider({ children }) { const [state, dispatch] = useReducer(appReducer, initialState); return <AppContext.Provider value={{ state, dispatch }}>{children}</AppContext.Provider>; } // 6. 自定义 Hook export function useAppContext() { const context = useContext(AppContext); if (!context) throw new Error('useAppContext must be used within AppProvider'); return context; }
2.2 使用状态管理
function Counter() { const { state, dispatch } = useAppContext(); return ( <div> <p>计数: {state.count}</p> <button onClick={() => dispatch({ type: 'INCREMENT' })}>+</button> <button onClick={() => dispatch({ type: 'DECREMENT' })}>-</button> </div> ); } function ThemeToggle() { const { state, dispatch } = useAppContext(); return ( <button onClick={() => dispatch({ type: 'TOGGLE_THEME' })}> 当前主题: {state.theme} </button> ); }
三、实战:Todo 应用
3.1 Store 定义
const initialState = { todos: [], filter: 'all', loading: false, error: null }; const ACTIONS = { ADD_TODO: 'ADD_TODO', TOGGLE_TODO: 'TOGGLE_TODO', DELETE_TODO: 'DELETE_TODO', SET_FILTER: 'SET_FILTER', SET_LOADING: 'SET_LOADING' }; function todoReducer(state, action) { switch (action.type) { case ACTIONS.ADD_TODO: return { ...state, todos: [...state.todos, action.payload] }; case ACTIONS.TOGGLE_TODO: return { ...state, todos: state.todos.map(todo => todo.id === action.payload ? { ...todo, completed: !todo.completed } : todo ) }; case ACTIONS.DELETE_TODO: return { ...state, todos: state.todos.filter(todo => todo.id !== action.payload) }; case ACTIONS.SET_FILTER: return { ...state, filter: action.payload }; default: return state; } }
四、性能优化
4.1 拆分 Context
// 按职责拆分,避免不必要的重渲染 const UserContext = createContext(); const ThemeContext = createContext(); const NotificationContext = createContext();
4.2 使用 useMemo 优化值
function AppProvider({ children }) { const [state, dispatch] = useReducer(reducer, initialState); const value = useMemo(() => ({ state, dispatch }), [state]); return <AppContext.Provider value={value}>{children}</AppContext.Provider>; }
五、小结
| 要点 | 说明 |
|---|
| 适用场景 | 中小型应用、跨层级状态 |
| 核心组合 | Context + useReducer |
| 性能优化 | 拆分 Context、useMemo |