图文并茂五分钟搞懂react中的reducer

news2025/1/20 10:43:54

什么是 reducer 函数? 为什么要用 reducer?

  • Reducer 是处理状态的另一种方式。通俗来讲,就是可以让你的复杂组件更加干净,代码更加优雅
  • 当你的组件里有好多个状态更新逻辑,并且有些是有一定关联性的,写多个useState会看起来很杂乱,为解决这个问题,我们可以将多个状态更新逻辑整合到一个外部函数,这个函数就是reducer
  • 整合业务逻辑

使用 reducer 整合状态逻辑

举个栗子:


从上图我们可以看到,目前这个组件有三个处理逻辑,我们写了三个处理函数,这个组件的每个事件处理程序都通过 setTasks 来更新状态。随着这个组件的不断迭代,其状态逻辑也会越来越多。现在看起来没有什么毛病,但是真实业务场景里,需求往往会更加复杂,我们可以使用下面的方式来让业务逻辑更加清晰明了:

将状态逻辑移到组件之外 reducer 函数中

  • 将设置状态的逻辑 修改 成 dispatch 的一个 action;
  • 编写 一个 reducer 函数;
  • 在你的组件中 使用 reducer

看了上面我画的图,是不是感觉reducer很简单哇~ 在真实项目中,我们通常会使用 switch 语句来编写reducer,就像下图

既然我们会写了,那该怎么使用呢?

代码

tasksReducer.js

export default function tasksReducer(tasks, action) {
  switch (action.type) {
    case 'added': {
      return [
        ...tasks,
        {
          id: action.id,
          text: action.text,
          done: false,
        },
      ];
    }
    case 'changed': {
      return tasks.map((t) => {
        if (t.id === action.task.id) {
          return action.task;
        } else {
          return t;
        }
      });
    }
    case 'deleted': {
      return tasks.filter((t) => t.id !== action.id);
    }
    default: {
      throw Error('未知 action:' + action.type);
    }
  }
}

App.js

import { useReducer } from 'react';
import AddTask from './AddTask.js';
import TaskList from './TaskList.js';
import tasksReducer from './tasksReducer.js';

export default function TaskApp() {
  const [tasks, dispatch] = useReducer(tasksReducer, initialTasks);

  function handleAddTask(text) {
    dispatch({
      type: 'added',
      id: nextId++,
      text: text,
    });
  }

  function handleChangeTask(task) {
    dispatch({
      type: 'changed',
      task: task,
    });
  }

  function handleDeleteTask(taskId) {
    dispatch({
      type: 'deleted',
      id: taskId,
    });
  }

  return (
    <>
      <h1>我今天要做什么呢?</h1>
      <AddTask onAddTask={handleAddTask} />
      <TaskList
        tasks={tasks}
        onChangeTask={handleChangeTask}
        onDeleteTask={handleDeleteTask}
      />
    </>
  );
}

let nextId = 3;
const initialTasks = [
  {id: 0, text: '吃饭', done: true},
  {id: 1, text: '睡觉', done: false},
  {id: 2, text: '打豆豆', done: false},
];

对比 useState 和 useReducer

我们观察上图,不难发现:

  • 参数:useReducer 和 useState 很相似,都有初始状态,useReducer 钩子接受 2 个参数: reducer 函数,初始的 state
  • 返回值:useReducer 会返回一个有状态的值和一个设置该状态的函数(在上面案例中就是 dispatch 函数)
  • 代码体积: 多事件相似方式修改 state 时,useReducer 可减少代码量
  • 可读性: 状态更新逻辑简单我们就可以用useState ,逻辑复杂,useReducer 可以将状态更新逻辑与事件处理程序分离
  • 可调试性: useState 出现问题不太好调试,而使用 useReducer 时, 可以在 reducer 函数打印日志

如何编写一个优雅的 reducer

  • reducers 必须纯粹。 即当输入相同时,输出也是相同的。它们不应该包含异步请求、定时器或者任何副作用(对组件外部有影响的操作)。
  • 每个 action 都描述了一个单一的用户交互,即使它会引发数据的多个变化。 举个例子,如果用户在一个由 reducer 管理的表单(包含五个表单项)中点击了 重置按钮,那么 dispatch 一个 reset_form 的 action 比 dispatch 五个单独的 set_field 的 action 更加合理。

还可以使用 Immer 简化 reducers

useImmerReducer 让你可以通过 push 或 arr[i] = 来修改 state。下图描述了,优化前后,代码确实有所减少哦~~

Reducers 应该是纯净的,而 Immer 提供了一种特殊的 draft 对象,可以通过它安全修改 state。Immer 在底层基于当前 state 创建一个副本。

今天就写到这里啦~

  • 小伙伴们,( ̄ω ̄( ̄ω ̄〃 ( ̄ω ̄〃)ゝ我们明天再见啦~~
  • 大家要天天开心哦

欢迎大家指出文章需要改正之处~
学无止境,合作共赢

在这里插入图片描述

欢迎路过的小哥哥小姐姐们提出更好的意见哇~~

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

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

相关文章

SPIFlash-W25QXX使用总结

W25QXX简介 W25QXX&#xff0c;后面的XX指的是Mbit 常见的型号有&#xff1a; W25Q80 W25Q16 W25Q32 W25Q64 W25Q128 注意80是表示8而不是80 所以&#xff0c;换算成字节数&#xff0c;从上到下为&#xff1a; 1MB 2MB 4MB 8MB 16MB 整个flash分成多个块&#xff0c;一个块分成…

Linux配置MySQL环境(三)

Linux配置MySQL环境 一、下载1. 官网下载MySQL2. 百度网盘快速下载MySQL 二、安装1、通过 Xftp 将 MySQL 安装包拷贝到 Linux2、解压缩3、安装 common、libs、client、server4、初步连接 三、卸载四、常用设置1. 修改 root 用户密码 五、使用新密码登录六、开启远程访问七、开放…

购物车按钮

先看效果&#xff1a; 再看代码&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>购物车按钮展示</title><link href"https://fonts.googleapis.com/css?familyInter:400…

002Mybatis初始化引入

引入依赖 <dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId> </dependency> 自动检测工程中的DataSource创建并注册SqlSessionFactory实例创建并注册SqlSessionTemplate实例自…

chatgpt赋能python:Python中如何输入一个列表?

Python中如何输入一个列表&#xff1f; 如果你正在使用Python编程语言&#xff0c;那么输入一个列表是很常见的任务。列表是Python中最常用的数据类型之一&#xff0c;它允许我们在一个变量中存储多个值。在这篇文章中&#xff0c;我们将介绍如何使用Python语言输入一个列表&a…

chatgpt赋能python:Python中的16进制输出:从基础到应用

Python中的16进制输出&#xff1a;从基础到应用 在计算机编程中&#xff0c;16进制是一种非常重要的数字系统。对于Python工程师来说&#xff0c;熟练地掌握16进制输出技能非常重要&#xff0c;因为它能够帮助你更好地理解和分析二进制数据。 在本篇文章中&#xff0c;我们将…

JavaSE-03 【流程控制语句】

第一章 流程控制 1.1 流程概述 在一个程序执行的过程中&#xff0c;每条语句的执行顺序对程序的结果是由直接影响的&#xff0c; 也就是&#xff0c;语句的流程对运行结果有着直接的影响&#xff0c;所以&#xff0c;必须清楚知道每条语句的执行流程&#xff0c; 并且&#x…

Gossip分布式通信协议副本管理器说明

Gossip中副本管理器 副本管理器状态 不考虑应用时一个副本管理器应该有的状态&#xff1a; 值&#xff0c;这是由副本管理器维护的应用状态的值&#xff0c;每个副本管理器是一个状态机。起始于一个特定的初始值。此后的状态完全由更新操作决定。值的时间戳&#xff1a;代表更…

chatgpt赋能python:Python的包管理器-pip

Python的包管理器 - pip 什么是pip? pip是Python中的一个包管理工具&#xff0c;它可以用来安装、升级以及管理Python语言中的第三方模块。 如何安装pip 在Python 2.7.9和Python 3.4中&#xff0c;pip已经随着Python自带安装了。 如果你的Python没有安装pip&#xff0c;可…

JavaSSM笔记(四)

MySQL高级 在JavaWeb阶段&#xff0c;我们初步认识了MySQL数据库&#xff0c;包括一些基本操作&#xff0c;比如创建数据库、表、触发器&#xff0c;以及最基本的增删改查、事务等操作。而在此阶段&#xff0c;我们将继续深入学习MySQL&#xff0c;了解它的更多高级玩法&#…

JavaSSM笔记(三)

SpringSecurity 本章我们会一边讲解SpringSecurity框架&#xff0c;一边从头开始编写图书管理系统。 SpringSecurity是一个基于Spring开发的非常强大的权限验证框架&#xff0c;其核心功能包括&#xff1a; 认证 &#xff08;用户登录&#xff09;授权 &#xff08;此用户能…

【From Audio to Talking Heads in Real-Time with AI! RAD-NeRF explained】

视频链接&#xff1a;RAD-NeRF https://me.kiui.moe/radnerf/videos/obama_intro.mp4 From Audio to Talking Heads in Real-Time with AI! RAD-NeRF explained Efficient NeRFs for Real-Time Portrait Synthesis (RAD-NeRF) We’ve heard of deepfakes, we’ve heard of N…

Nacos架构与原理 - 配置模型

文章目录 背景概念介绍配置(Configuration)配置管理 (Configuration Management)配置服务 (Configuration Service)配置项&#xff08;Configuration Item&#xff09;配置集&#xff08;Configuration Set&#xff09;命名空间&#xff08;Namespace&#xff09;配置组&#x…

chatgpt赋能python:Python中如何实现print不换行

Python中如何实现print不换行 在编写Python程序时&#xff0c;我们经常需要使用print语句来输出信息。然而&#xff0c;有时候我们希望在输出信息时不换行&#xff0c;而是将多个输出信息打印在同一行上。这里介绍几种Python中print不换行的方式。 方法一&#xff1a;使用逗号…

Redis7分布式缓存

Redis7分布式缓存 一、Redis入门概述1.主流功能与应用2.命名规则 二、Redis 10 大数据类型1.redis字符串 (String)2. redis列表 (List)3. redis哈希表 (Hash)4. redis集合 (Set)5. redis有序集合 (ZSet)6. redis地理空间(GEO)7. redis基数统计 (HyperLogLog)8. redis位图 (bitm…

wavemlp怎么运行的

1.首先&#xff0c;输入进来的x是batchsize&#xff0c;64&#xff0c;256&#xff0c;256尺寸的。 他会用四个不同的conv组合&#xff0c;theta组合是由二维卷积&#xff08;batchnorm和relu的&#xff09;&#xff0c;得到两个值。 而&#xff0c;x_h和x_w都是通过一个简单…

JavaSE笔记(四)重制版

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eFLuY3vJ-1685927553034)(https://s2.loli.net/2022/09/22/lmKBNFc5wPEgjaS.png)] 面向对象高级篇 经过前面的学习&#xff0c;我们已经了解了面向对象编程的大部分基础内容&#xff0c;这一部分&…

一种新颖的智能优化算法—海鸥优化(SOA)算法

目录 一、SOA理论基础 二、ACO数学模型 2.1 迁徙 2.2 攻击 三、SOA伪代码 四、SOA运行结果 海鸥优化算法(Seagull Optimization Algorithm, SOA)是在2019年由 Dhiman 提出的一种受自然界海鸥启发的新颖全局优化算法&#xff0c;模拟了海鸥群体的迁徙和攻击行为。 一、SOA…

chatgpt赋能python:Python中如何实现1到100的循环?

Python中如何实现1到100的循环&#xff1f; 在Python中&#xff0c;实现1到100的循环非常简单。我们可以通过for循环、while循环和列表生成式来实现这个任务。 1. 使用for循环实现1到100的循环 使用for循环可以让我们轻松地遍历从1到100的整数。这种方法很适合在循环中需要进…

chatgpt赋能python:Python中的UTF-8

Python中的UTF-8 什么是UTF-8&#xff1f; 在开始介绍Python中的UTF-8&#xff0c;让我们先了解什么是UTF-8。UTF-8是一种Unicode字符集的编码方法&#xff0c;可以表示全球范围内的字符集&#xff0c;包括机器语言和人类语言。 Python和UTF-8 Python是一种高级编程语言&am…