【react】 useReducer 集中式管理组件的状态

useReducer 集中式管理组件的状态

1️⃣ 基本概念

useReducer 是 React 提供的 管理组件状态的一种 Hook ,功能上类似于 useState,但是它更适合状态逻辑复杂或依赖前一个状态的情况

它的核心思想:

  • 状态(state) 是不可变的。
  • 状态更新逻辑 写在一个函数里(Reducer)。
  • 通过 dispatch(action) 来触发状态更新,而不是直接 setState。

1.1 函数签名

scss 复制代码
const [state, dispatch] = useReducer(reducer, initialState, init?)

参数解释:

参数 说明
reducer 一个函数 (state, action) => newState,决定状态如何更新
initialState 初始状态
init 可选函数,用于惰性初始化状态(通常不需要)

返回值:

  • state:当前状态(只读)
  • dispatch:派发 action 的函数,用来触发状态更新

1.2 Reducer 函数

Reducer 是状态更新逻辑的核心:

php 复制代码
function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return { count: state.count + 1 };
    case 'decrement':
      return { count: state.count - 1 };
    case 'reset':
      return { count: 0 };
    default:
      return state;
  }
}

特点:

  • 不直接修改 state,而是返回一个新的状态对象
  • 通常使用 switch(action.type) 来判断不同动作。
  • action 可以是对象,也可以是任意自定义格式(推荐对象,包含 type 字段)。

1.3 最简单的例子

javascript 复制代码
import React, { useReducer } from 'react';

const initialState = { count: 0 };

function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return { count: state.count + 1 };
    case 'decrement':
      return { count: state.count - 1 };
    case 'reset':
      return { count: 0 };
    default:
      return state;
  }
}

function Counter() {
  const [state, dispatch] = useReducer(reducer, initialState);

  return (
    <div>
      <p>Count: {state.count}</p>
      <button onClick={() => dispatch({ type: 'increment' })}>+</button>
      <button onClick={() => dispatch({ type: 'decrement' })}>-</button>
      <button onClick={() => dispatch({ type: 'reset' })}>Reset</button>
    </div>
  );
}

export default Counter;

✅ 可以看到:

  • 所有状态更新逻辑都集中在 reducer 里。
  • 组件内部不需要关心更新细节,只需要 dispatch 对应的 action。

2️⃣ useReducer vs useState

方面 useState useReducer
适用场景 简单状态(计数器、输入框) 复杂状态逻辑、多个子值依赖前一个状态
状态更新 setState(newValue) dispatch(action)
状态逻辑 分散在多个 setState 集中在 reducer 函数
可读性 简单 状态逻辑清晰、易于维护
性能优化 不如 useReducer dispatch 不会改变引用,可避免重复渲染

总结

  • 简单场景用 useState 就够了。
  • 状态更新复杂(多分支、多子值依赖)用 useReducer 更清晰。

3️⃣ 更复杂的例子:表单管理

假设有一个复杂表单:

javascript 复制代码
import React, { useReducer } from 'react';

const initialState = {
  username: '',
  email: '',
  password: '',
};

function reducer(state, action) {
  switch (action.type) {
    case 'updateField':
      return { ...state, [action.field]: action.value };
    case 'reset':
      return initialState;
    default:
      return state;
  }
}

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

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

  const handleReset = () => {
    dispatch({ type: 'reset' });
  };

  return (
    <form>
      <input name="username" value={state.username} onChange={handleChange} placeholder="Username" />
      <input name="email" value={state.email} onChange={handleChange} placeholder="Email" />
      <input name="password" type="password" value={state.password} onChange={handleChange} placeholder="Password" />
      <button type="button" onClick={handleReset}>Reset</button>
    </form>
  );
}

export default Form;

✅ 优点:

  • 所有字段更新逻辑集中在 reducer 中。
  • 方便扩展,比如添加表单校验、提交状态等。

4️⃣ useReducer 的惰性初始化

有时候初始化 state 很复杂,可以用第三个参数 init

kotlin 复制代码
function init(initialCount) {
  return { count: initialCount };
}

const [state, dispatch] = useReducer(reducer, 0, init);

好处:

  • 性能优化 :只有第一次 render 会调用 init
  • 避免每次 render 都执行复杂计算。

5️⃣ 总结

  1. useReducer 是 useState 的增强版,适合复杂状态逻辑。

  2. 核心概念

    • Reducer:决定状态如何变化
    • State:组件状态(只读)
    • Dispatch:触发状态更新
  3. 优点

    • 状态更新逻辑集中,易维护
    • 方便管理复杂或嵌套状态
    • 和 Redux 思想一致,易迁移
  4. 使用场景

    • 多个状态值相互依赖

    • 多分支的状态更新逻辑

    • 想用 dispatch(action) 统一管理

总结

useReducer 管理的 state 本身只会在 dispatch 被调用时改变。每次组件重新渲染时,整个组件函数会重新执行,但 state 不会自动变化,仍然保持最新的值

相关推荐
源心锁1 小时前
👋 手搓 gzip 实现的文件分块压缩上传
前端·javascript
源心锁1 小时前
丧心病狂!在浏览器全天候记录用户行为排障
前端·架构
GIS之路2 小时前
GDAL 实现投影转换
前端
烛阴2 小时前
从“无”到“有”:手动实现一个 3D 渲染循环全过程
前端·webgl·three.js
BD_Marathon2 小时前
SpringBoot——辅助功能之切换web服务器
服务器·前端·spring boot
Kagol2 小时前
JavaScript 中的 sort 排序问题
前端·javascript
eason_fan2 小时前
Service Worker 缓存请求:前端性能优化的进阶利器
前端·性能优化
光影少年3 小时前
rn如何和原生进行通信,是单线程还是多线程,通信方式都有哪些
前端·react native·react.js·taro
好大哥呀3 小时前
Java Web的学习路径
java·前端·学习
HashTang3 小时前
【AI 编程实战】第 7 篇:登录流程设计 - 多场景、多步骤的优雅实现
前端·uni-app·ai编程