无废话之 高级状态管理:useContext + useReducer 架构教程

55 阅读2分钟

React 本身并不强制你使用 Redux 等外部库,但借助 useContext + useReducer,就能实现“小型 Redux”的全局状态管理架构。

它的特点:

  • 全局状态共享
  • 集中式更新逻辑(类似 Redux)
  • 组件无须一层层 props 传递
  • 内置 Hooks,不依赖第三方库
  • 可拆分模块,维护清晰

下面带你从原理到实战一步搞定。

1. 为什么要用 useContext + useReducer

🔥 适用场景

  • 全局共享状态(用户信息、主题设置、语言等)
  • 多组件都需要读写同一份数据
  • 状态更新逻辑复杂(大量 if/else)
  • 希望将逻辑与 UI 分离(更清晰、更可维护)

❌ useState 不适合做全局共享状态

因为:

  • 需要 props 层层传递
  • 状态逻辑散落在多个组件中
  • 难以维护

2. 核心架构图(非常重要)

[ Context Provider ]
      |
      V
[ useReducer ]  ------> reducer.js(更新逻辑)
      |
      V
[ 全局状态 state ]
      |
      V
[ 任何子组件 useContext ]  ——(读取/dispatch)

本质就是:

useContext 做“全局共享”,useReducer 做“统一更新逻辑”。

3. 实战:搭建一个全局用户管理 Store

以管理用户登录状态为例:

Step 1:定义 reducer(action + 更新逻辑)

store/userReducer.js

export const initialState = {
  user: null,
  isLogin: false
};

export function userReducer(state, action) {
  switch (action.type) {
    case "LOGIN":
      return {
        ...state,
        user: action.payload,
        isLogin: true
      };
    case "LOGOUT":
      return {
        ...state,
        user: null,
        isLogin: false
      };
    default:
      return state;
  }
}

Step 2:创建 Context Provider(状态容器)

store/UserContext.js

import { createContext, useReducer } from "react";
import { userReducer, initialState } from "./userReducer";

export const UserContext = createContext();

export function UserProvider({ children }) {
  const [state, dispatch] = useReducer(userReducer, initialState);

  return (
    <UserContext.Provider value={{ state, dispatch }}>
      {children}
    </UserContext.Provider>
  );
}

这一步很核心:

  • state:全局状态
  • dispatch:提交 action
  • 子组件通过 Context 获取

Step 3:在应用入口包裹 Provider

index.js 或 App.js

import { UserProvider } from "./store/UserContext";

export default function App() {
  return (
    <UserProvider>
      <HomePage />
    </UserProvider>
  );
}

Step 4:任意子组件使用全局状态

读取用户信息

const { state } = useContext(UserContext);

return <div>当前用户:{state.user?.name}</div>;

登录/登出(使用 dispatch)

const { dispatch } = useContext(UserContext);

function login() {
  dispatch({
    type: "LOGIN",
    payload: { name: "Tom", id: 1 }
  });
}

function logout() {
  dispatch({ type: "LOGOUT" });
}

4. 分模块:适合中大型应用

如果状态很多,可以拆多个 store:

/store
  /user
    userReducer.js
    UserContext.js
  /theme
    themeReducer.js
    ThemeContext.js

每个模块独立,可组合使用。

5. 注意事项

⚠ 避免 Context 频繁刷新

Provider 的 value 变化会导致所有子组件 rerender。
如果你状态频繁更新:

建议拆成多个 Context:

  • UserContext
  • ThemeContext
  • SettingsContext

6. useContext + useReducer vs Redux

useContext + useReducerRedux
复杂度简单中/高
依赖需要安装
大型项目一般✔ 最适合
调试工具✔ Redux DevTools
代码架构自由严格规范

总结

小项目 → useContext + useReducer
大项目 → Redux Toolkit