react - useReducer复杂状态管理

文章目录

    • [一、什么是 useReducer?](#一、什么是 useReducer?)
      • [📘 基本语法:](#📘 基本语法:)
    • 二、简单例子:计数器
    • [三、useReducer 与 useState 的区别](#三、useReducer 与 useState 的区别)
    • [四、reducer 的核心思想:纯函数](#四、reducer 的核心思想:纯函数)
    • 五、复杂状态示例:表单管理
    • [六、惰性初始化(Lazy Initialization)](#六、惰性初始化(Lazy Initialization))
    • [七、配合 Context 做全局状态管理](#七、配合 Context 做全局状态管理)
    • 八、最佳实践总结

当你的组件状态逻辑变得复杂、多个状态相互依赖时,

使用多个 useState 会让代码难以维护。

这时候,useReducer 就是更优雅的解决方案。

它让你用一种 类似 Redux 的思维 管理组件状态。

一、什么是 useReducer?

useReducer 是 React 提供的一个 Hook,用于以 "状态 + 动作(state + action)" 的方式管理状态。

简单来说,它是 useState 的替代方案,当状态逻辑复杂时,更容易组织和调试。

📘 基本语法:

ts 复制代码
const [state, dispatch] = useReducer(reducer, initialState);
参数 类型 说明
reducer (state, action) => newState 状态更新逻辑函数
initialState any 初始状态
返回值 [state, dispatch] 当前状态 + 派发函数

二、简单例子:计数器

js 复制代码
import React, { useReducer } from "react";

// 1️⃣ 定义 reducer 函数
function reducer(state, action) {
  switch (action.type) {
    case "increment":
      return { count: state.count + 1 };
    case "decrement":
      return { count: state.count - 1 };
    default:
      return state;
  }
}

// 2️⃣ 初始化 state
const initialState = { count: 0 };

// 3️⃣ 在组件中使用
function Counter() {
  const [state, dispatch] = useReducer(reducer, initialState);

  return (
    <div>
      <h2>计数:{state.count}</h2>
      <button onClick={() => dispatch({ type: "decrement" })}>-1</button>
      <button onClick={() => dispatch({ type: "increment" })}>+1</button>
    </div>
  );
}

export default Counter;

✅ 优点:

  • 状态更新逻辑集中、可预测;
  • 每个操作都有"类型(action.type)";
  • 容易扩展与调试。

三、useReducer 与 useState 的区别

对比项 useState useReducer
使用场景 状态简单 状态复杂、逻辑多分支
状态更新 直接赋值 通过 dispatch(action)
可维护性 难以追踪多个状态变化 状态集中管理
类似 Redux ❌ 否 ✅ 是
性能优化 简单 支持 lazy initialization 等高级用法

👉 简单总结:

useState 适合"一个按钮改一个状态"; useReducer 适合"多个状态随一个动作变化"。

四、reducer 的核心思想:纯函数

reducer 是一个纯函数(Pure Function)

给定相同的输入,一定返回相同的输出,且没有副作用

js 复制代码
function reducer(state, action) {
  // ❌ 不允许修改 state 本身
  // ✅ 必须返回一个新的 state
  return { ...state, count: state.count + 1 };
}

⚠️ 不要在 reducer 里做:

  • 异步操作(如 fetch)
  • DOM 操作
  • 改变外部变量

这些属于"副作用",应该在 useEffect 或中间层执行。

五、复杂状态示例:表单管理

js 复制代码
import React, { useReducer } from "react";

const initialState = { name: "", email: "", age: "" };

function formReducer(state, action) {
  switch (action.type) {
    case "CHANGE_FIELD":
      return { ...state, [action.field]: action.value };
    case "RESET":
      return initialState;
    default:
      return state;
  }
}

function Form() {
  const [state, dispatch] = useReducer(formReducer, initialState);

  const handleChange = (e) => {
    dispatch({
      type: "CHANGE_FIELD",
      field: e.target.name,
      value: e.target.value
    });
  };

  return (
    <form>
      <input name="name" value={state.name} onChange={handleChange} placeholder="姓名" />
      <input name="email" value={state.email} onChange={handleChange} placeholder="邮箱" />
      <input name="age" value={state.age} onChange={handleChange} placeholder="年龄" />
      <button type="button" onClick={() => dispatch({ type: "RESET" })}>
        重置
      </button>
      <pre>{JSON.stringify(state, null, 2)}</pre>
    </form>
  );
}

export default Form;

✅ 优点:

  • 所有表单逻辑集中在 reducer 中;
  • 可轻松扩展更多字段;
  • 结构清晰,便于维护。

六、惰性初始化(Lazy Initialization)

有时初始 state 的计算很耗时(例如从 localStorage 获取)。我们可以使用 useReducer 的第三个参数来延迟初始化

js 复制代码
function init(initialCount) {
  return { count: initialCount * 2 };
}

function reducer(state, action) {
  switch (action.type) {
    case "increment":
      return { count: state.count + 1 };
    default:
      return state;
  }
}

function Counter() {
  const [state, dispatch] = useReducer(reducer, 5, init); // 惰性初始化

  return (
    <div>
      <h2>Count: {state.count}</h2>
      <button onClick={() => dispatch({ type: "increment" })}>+1</button>
    </div>
  );
}

💡 这样 init 只会在首次渲染执行一次,性能更好,避免了重复计算。

七、配合 Context 做全局状态管理

useReducer 还能配合 useContext 实现 轻量级全局状态管理(类似 Redux)。

js 复制代码
import React, { createContext, useReducer, useContext } from "react";

const StoreContext = createContext();

const initialState = { theme: "light" };

function reducer(state, action) {
  switch (action.type) {
    case "TOGGLE_THEME":
      return { theme: state.theme === "light" ? "dark" : "light" };
    default:
      return state;
  }
}

export function StoreProvider({ children }) {
  const [state, dispatch] = useReducer(reducer, initialState);
  return <StoreContext.Provider value={{ state, dispatch }}>{children}</StoreContext.Provider>;
}

export function useStore() {
  return useContext(StoreContext);
}

然后在任意组件中使用:

js 复制代码
function ThemeSwitcher() {
  const { state, dispatch } = useStore();

  return <button onClick={() => dispatch({ type: "TOGGLE_THEME" })}>当前主题:{state.theme}</button>;
}

✅ 好处:

  • 无需引入 Redux;
  • 状态集中管理;
  • 组件解耦、逻辑清晰。

八、最佳实践总结

建议 说明
✅ 状态复杂时优先考虑 useReducer 结构清晰,可维护性高
✅ reducer 必须是纯函数 保证可预测性
✅ Action type 使用常量 避免拼写错误
✅ 结合 Context 实现全局状态 小型项目的轻量级 Redux
❌ 不要在 reducer 中发请求或做副作用 会破坏纯函数特性

👉点击进入 我的网站

相关推荐
林深现海15 分钟前
Jetson Orin nano/nx刷机后无法打开chrome/firefox浏览器
前端·chrome·firefox
黄诂多28 分钟前
APP原生与H5互调Bridge技术原理及基础使用
前端
前端市界32 分钟前
用 React 手搓一个 3D 翻页书籍组件,呼吸海浪式翻页,交互体验带感!
前端·架构·github
早點睡39033 分钟前
高级进阶 ReactNative for Harmony 项目鸿蒙化三方库集成实战:react-native-drag-sort
react native·react.js·harmonyos
文艺理科生33 分钟前
Nginx 路径映射深度解析:从本地开发到生产交付的底层哲学
前端·后端·架构
千寻girling34 分钟前
主管:”人家 Node 框架都用 Nest.js 了 , 你怎么还在用 Express ?“
前端·后端·面试
C澒43 分钟前
Vue 项目渐进式迁移 React:组件库接入与跨框架协同技术方案
前端·vue.js·react.js·架构·系统架构
xiaoxue..1 小时前
合并两个升序链表 与 合并k个升序链表
java·javascript·数据结构·链表·面试
清山博客1 小时前
OpenCV 人脸识别和比对工具
前端·webpack·node.js
要加油哦~1 小时前
AI | 实践教程 - ScreenCoder | 多agents前端代码生成
前端·javascript·人工智能