React hook之userReducer

news2025/6/6 19:31:20

在 React 中,useReducer 是一个用于管理复杂状态逻辑的 Hook,它类似于 Redux 中的 reducer 模式,但更轻量且适用于组件内部或结合 Context API 实现全局状态管理。以下是 useReducer 的详细用法指南:


1. 基本语法

const [state, dispatch] = useReducer(reducer, initialState);
  • reducer:一个函数,接收当前状态和 action,返回新状态。
  • initialState:状态的初始值。
  • state:当前状态。
  • dispatch:用于触发状态更新的函数(发送 action)。

2. 核心概念

(1) Reducer 函数

Reducer 的格式:(state, action) => newState

  • action:通常是一个对象,包含 type(操作类型)和可选的 payload(数据)。
  • 必须返回新状态(不可直接修改原状态!)。
function reducer(state, action) {
  switch (action.type) {
    case 'INCREMENT':
      return { ...state, count: state.count + 1 };
    case 'DECREMENT':
      return { ...state, count: state.count - 1 };
    case 'SET_VALUE':
      return { ...state, value: action.payload };
    default:
      return state; // 默认返回原状态
  }
}
(2) Dispatch Action

通过 dispatch 发送 action 来更新状态:

dispatch({ type: 'INCREMENT' });
dispatch({ type: 'SET_VALUE', payload: 42 });

3. 完整示例

计数器组件
import { useReducer } from 'react';

// 定义 reducer
function counterReducer(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(counterReducer, { count: 0 });

  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>
  );
}

4. 进阶用法

(1) 结合 Payload 传递数据
dispatch({ type: 'SET_NAME', payload: 'Alice' });

// Reducer 处理
case 'SET_NAME':
  return { ...state, name: action.payload };
(2) 惰性初始化

如果初始状态需要计算,可以传入一个初始化函数:

function init(initialCount) {
  return { count: initialCount };
}

const [state, dispatch] = useReducer(reducer, initialCount, init);
(3) 结合 Context API 实现全局状态
// 创建 Context
const CounterContext = createContext();

// Provider 组件
function CounterProvider({ children }) {
  const [state, dispatch] = useReducer(counterReducer, { count: 0 });
  return (
    <CounterContext.Provider value={{ state, dispatch }}>
      {children}
    </CounterContext.Provider>
  );
}

// 子组件中使用
function ChildComponent() {
  const { state, dispatch } = useContext(CounterContext);
  // ...
}

5. 与 useState 的对比

场景useStateuseReducer
简单状态适合(如布尔值、数字)过度设计
复杂状态逻辑代码冗长(需多个 useState适合(逻辑集中管理)
依赖前一个状态需用函数更新(setCount(c => c + 1)自动处理(reducer 接收当前状态)
跨组件共享状态需结合 Context更适合(与 Context 天然搭配)

6. 最佳实践

  1. 拆分 Reducer
    如果逻辑复杂,可以按功能拆分成多个 reducer,再用 combineReducers(类似 Redux):

    function rootReducer(state, action) {
      return {
        counter: counterReducer(state.counter, action),
        user: userReducer(state.user, action),
      };
    }
    
  2. 避免深层嵌套状态
    尽量扁平化状态结构,便于更新。

  3. 异步操作
    dispatch 外处理异步逻辑(如 API 请求),完成后调用 dispatch

    async function fetchData(dispatch) {
      const data = await api.get();
      dispatch({ type: 'SET_DATA', payload: data });
    }
    

7. 示例:Todo 列表

function todoReducer(state, action) {
  switch (action.type) {
    case 'ADD_TODO':
      return [...state, { text: action.payload, completed: false }];
    case 'TOGGLE_TODO':
      return state.map((todo, index) =>
        index === action.payload
          ? { ...todo, completed: !todo.completed }
          : todo
      );
    default:
      return state;
  }
}

function TodoApp() {
  const [todos, dispatch] = useReducer(todoReducer, []);
  const [input, setInput] = useState('');

  const handleSubmit = (e) => {
    e.preventDefault();
    dispatch({ type: 'ADD_TODO', payload: input });
    setInput('');
  };

  return (
    <div>
      <form onSubmit={handleSubmit}>
        <input value={input} onChange={(e) => setInput(e.target.value)} />
      </form>
      <ul>
        {todos.map((todo, index) => (
          <li
            key={index}
            onClick={() => dispatch({ type: 'TOGGLE_TODO', payload: index })}
            style={{ textDecoration: todo.completed ? 'line-through' : 'none' }}
          >
            {todo.text}
          </li>
        ))}
      </ul>
    </div>
  );
}

总结

  • 何时用 useReducer
    状态逻辑复杂、需要依赖前一个状态、或需要跨组件共享状态时。
  • 优势:逻辑集中、易于测试、适合与 Context 结合。
  • 注意:避免过度使用,简单场景直接用 useState 更高效。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2402029.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Dify源码教程:账户和密码传递分析

概述 Dify系统中账户创建过程中的密码处理是Web应用安全的重要环节。本教程详细分析了从前端表单到后端存储的完整流程&#xff0c;展示了Dify如何安全地处理用户凭据。 前端部分 在 dify/web/app/install/installForm.tsx 文件中&#xff0c;当用户填写完表单并点击安装按钮…

数据分析图表类型及其应用场景

说明&#xff1a;顶部HTML文件下载后可以直接查看&#xff0c;带有示图。 摘要 数据可视化作为现代数据分析的核心环节&#xff0c;旨在将复杂、抽象的数据转化为直观、易懂的图形形式。这种转化显著提升了业务决策能力&#xff0c;优化了销售与营销活动&#xff0c;开辟了新…

Github 2025-06-03Python开源项目日报 Top10

根据Github Trendings的统计&#xff0c;今日(2025-06-03统计)共有10个项目上榜。根据开发语言中项目的数量&#xff0c;汇总情况如下&#xff1a; 开发语言项目数量Python项目10Rust项目1HTML项目1C项目1 系统设计指南 创建周期&#xff1a;2507 天开发语言&#xff1a;Pyt…

电脑提示dll文件缺失怎么办 dll修复方法

当你在使用某些应用程序或启动电脑时&#xff0c;看到提示“DLL文件缺失”的错误信息&#xff0c;这通常意味着某个必要的动态链接库&#xff08;DLL&#xff09;文件无法被找到或加载&#xff0c;导致软件无法正常运行。本文将详细介绍如何排查和修复DLL文件缺失的问题&#x…

【自动思考记忆系统】demo (Java版)

背景&#xff1a;看了《人工智能》中的一段文章&#xff0c;于是有了想法。想从另一种观点&#xff08;⭕️&#xff09;出发&#xff0c;尝试编码&#xff0c;告别传统程序员一段代码解决一个问题的方式。下图是文章原文和我的思考涂鸦✍️&#xff0c;于是想写一个自动思考记…

51单片机基础部分——独立按键检测

前言 在单片机开发中&#xff0c;我们会经常对单片机的状态进行控制&#xff0c;比如我们会控制某个灯点亮&#xff0c;某个灯熄灭&#xff0c;这个时候我们就要开始做控制&#xff0c;我们可以通过什么控制呢&#xff0c;这个地方我们选择按键控制 按键实物及工作原理 生活…

【Docker管理工具】部署Docker可视化管理面板Dpanel

【Docker管理工具】部署Docker可视化管理面板Dpanel 一、Dpanel介绍1.1 DPanel 简介1.2 主要特点 二、本次实践规划2.1 本地环境规划2.2 本次实践介绍 三、本地环境检查3.1 检查Docker服务状态3.2 检查Docker版本3.3 检查docker compose 版本 四、下载Dpanel镜像五、部署Dpanel…

springboot实现查询学生

文章目录 数据库前端 请求mybatis 数据库 前端 请求 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Title</title> </head> <body> <a href"/list">启动学生管理…

Appium+python自动化(九)- 定位元素工具

简介 环境搭建好了&#xff0c;其他方面的知识也准备的差不多了&#xff0c;那么就开始下一步元素定位&#xff0c;元素定位主要介绍如何使用uiautomatorviewer&#xff0c;通过定位到页面上的元素&#xff0c;然后进行相应的点击等操作. 此外在介绍另一款工具&#xff1a;Insp…

Unity 中实现可翻页的 PageView

之前已经实现过&#xff1a; Unity 中实现可复用的 ListView-CSDN博客文章浏览阅读5.6k次&#xff0c;点赞2次&#xff0c;收藏27次。源码已放入我的 github&#xff0c;地址&#xff1a;Unity-ListView前言实现一个列表组件&#xff0c;表现方面最核心的部分就是重写布局&…

云计算 Linux Rocky day05【rpm、yum、history、date、du、zip、ln】

云计算 Linux Rocky day05【rpm、yum、history、date、du、zip、ln】 目录 云计算 Linux Rocky day05【rpm、yum、history、date、du、zip、ln】1.RPM包的一般安装位置2.软件名和软件包名3.查询软件信息4.查询软件包5.导入红帽签名信息&#xff0c;解决查询软件包信息报错6.利用…

LuaJIT2.1 和 Lua5.4.8 性能对比

说明 最近在学习 LuaJIT&#xff0c;想看看把它接入到项目中使用&#xff0c;会提高多大的性能。 今天抽时间&#xff0c;简单地测试了一下 LuaJIT 2.2 和 Lua5.4.8 的性能。 测试平台&#xff1a; 系统&#xff1a;Windows 10 WSLCPU&#xff1a;Intel Core™ i7-8700 CPU…

深入解析与解决方案:处理Elasticsearch中all found copies are either stale or corrupt未分配分片问题

目录 引言 1 问题诊断深入分析 1.1 错误含义深度解析 1.2 获取详细的诊断信息 2 解决方案选择与决策流程 2.1 可用选项全面对比 2.2 推荐处理流程与决策树 3 具体操作步骤详解 3.1 优先尝试 - 分配最新副本&#xff08;最低风险&#xff09; 3.2 中等风险方案 - 分配…

【NLP 78、手搓Transformer模型结构】

你以为走不出的淤泥&#xff0c;也迟早会云淡风轻 —— 25.5.31 引言 ——《Attention is all you need》 《Attention is all you need》这篇论文可以说是自然语言处理领域的一座里程碑&#xff0c;它提出的 Transformer 结构带来了一场技术革命。 研究背景与目标 在 Transfo…

如何自定义WordPress主题(5个分步教程)

如果您已经安装了一个 WordPress 主题&#xff0c;但它不太适合您&#xff0c;您可能会感到沮丧。在定制 WordPress 主题方面&#xff0c;您有很多选择。 挑战在于找到正确的方法。 在本篇文章中&#xff0c;我将引导您了解自定义 WordPress 主题的各种选项&#xff0c;帮助您…

react实现markdown文件预览

文章目录 react实现markdown文件预览1、实现md文件预览2、解决图片不显示3、实现效果 react实现markdown文件预览 1、实现md文件预览 1️⃣第一步&#xff1a;安装依赖&#xff1a; npm install react-markdown remark-gfmreact-markdown&#xff1a;将 Markdown 渲染为 Rea…

PDF处理控件Aspose.PDF教程:在 C# 中更改 PDF 页面大小

PDF 的页面大小决定了其内容的显示、打印或处理方式。我们通常在准备打印、转换格式或标准化布局时需要更改 PDF 页面大小。在本文中&#xff0c;您将学习如何使用 C# 更改任何 PDF 文件的页面大小。我们将通过完整的代码示例&#xff0c;逐步指导您完成操作。 Aspose.PDF最新…

rust或tauri项目执行命令的时候,cmd窗口也会弹出显示解决方法

阻止 Tauri 执行命令时弹出 CMD 窗口 当你在 Tauri 中使用 tokio::process::Command 执行命令时弹出 CMD 窗口&#xff0c;这是因为 Windows 默认会为控制台程序创建可见窗口。以下是几种解决方法&#xff1a; 1. 使用 Windows 特有的创建标志 (推荐) #[tauri::command] pub…

使用Python进行函数作画

前言 因为之前通过deepseek绘制一下卡通的人物根本就不像&#xff0c;又想起来之前又大佬通过函数绘制了一些图像&#xff0c;想着能不能用Python来实现&#xff0c;结果发现可以&#xff0c;不过一些细节还是需要自己调整&#xff0c;deepseek整体的框架是没有问题&#xff0…

微型导轨在手术机器人领域中有哪些关键操作?

在微创手术领域&#xff0c;手术机器人凭借其高精度、高稳定性和远程操控能力&#xff0c;正逐步成为现代外科手术的重要工具。微型导轨作为一种专为高精度运动设计的线性导向系统&#xff0c;凭借其亚微米级定位精度、低摩擦运动特性及紧凑结构设计&#xff0c;已成为手术机器…