【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 不会自动变化,仍然保持最新的值

相关推荐
aixingpan2 分钟前
aixingpan.cn API开发文档:api_docs_bichart_natalvstertiary2接口指南
前端·php
铁皮饭盒11 分钟前
网页端, 40mb离线模型, 自动抠图, 不用 Python,不用服务器,不用 API Key, 不用显卡
前端·javascript·后端
梦曦i13 分钟前
修复 .uvue 页面路径残留问题
前端·vite
nicole bai17 分钟前
vue前端全局图标闪一下的问题
前端·vue.js
ly768918 分钟前
磁盘 I/O 延迟突增:用 iostat、blktrace 与火焰图定位到具体调用栈
java·linux·前端·数据库·iostat·磁盘 i/o·blktrace
IT_陈寒25 分钟前
Redis并发写入踩坑记录:别让超时设置坑了你
前端·人工智能·后端
晨枫阳25 分钟前
Client authentication(客户端授权)开关与OAuth2 PKCE的深刻理解
前端·安全
福兮说25 分钟前
在浏览器里写一个“够用就好“的 Excel 公式求值器
前端·javascript·excel·编译原理
志尊宝39 分钟前
Vue3 零基础每日笔记(027):组件上的 v-model——让自定义组件也能双向绑定
前端·javascript·vue.js·笔记·html5
萧行之3 小时前
可视化技术复盘:从图形语法看 D3、Vega-Lite、ECharts、Observable Plot
前端·学习·数据可视化