React(react18)中组件通信04——redux入门
React(react18)中组件通信04——redux入门
- 1. 前言
- 1.1 React中组件通信的其他方式
- 1.2 介绍redux
- 1.2.1 参考官网
- 1.2.2 redux原理图
- 1.2.3 redux基础介绍
- 1.2.3.1 action
- 1.2.3.2 store
- 1.2.3.3 reducer
- 1.3 安装redux
- 2. redux入门例子
- 3. redux入门例子——优化1(reducer 和 store拆开)
- 3.1 想要实现的效果
- 3.2 代码设计
- 3.3 添加 重新渲染
- 3.4 附代码
- 4. redux入门例子——优化2(拆出action)
- 4.1 关于action的其他说明
- 4.2 优化——拆出action
- 4.3 优化——动态加减数字
- 4.3.1 优化看效果
- 4.3.2 附代码
1. 前言
1.1 React中组件通信的其他方式
- React(react18)中组件通信01——props.
- React(react18)中组件通信02——消息订阅与发布、取消订阅以及卸载组件时取消订阅.
- React(react18)中组件通信03——简单使用 Context 深层传递参数.
1.2 介绍redux
1.2.1 参考官网
- 讲解、例子,参考官网,官网地址如下:
Redux 中文文档——https://www.redux.org.cn/.
1.2.2 redux原理图
- 原理图,如下:
- 简单解释
- 要想更新 state 中的数据,你需要发起一个 action。
Action
就是一个普通 JavaScript 对象(注意到没,这儿没有任何魔法?)用来描述发生了什么。 - 强制使用 action 来描述所有变化带来的好处是可以清晰地知道应用中到底发生了什么。如果一些东西改变了,就可以知道为什么变。action 就像是描述发生了什么的指示器。
- 最终,为了把 action 和 state 串起来,开发一些函数,这就是
reducer
。再次地强调,没有任何魔法,reducer 只是一个接收 state 和 action,并返回新的 state 的函数,并且是一个纯函数。 - 而整个应用的 state 被储存在一棵 object tree 中,并且这个 object tree 只存在于唯一一个
store
中。
- 要想更新 state 中的数据,你需要发起一个 action。
1.2.3 redux基础介绍
1.2.3.1 action
- Action 是把数据从应用(这里之所以不叫 view 是因为这些数据有可能是服务器响应,用户输入或其它非 view 的数据 )传到 store 的有效载荷。它是 store 数据的唯一来源。一般来说你会通过
store.dispatch()
将 action 传到 store。 - Action 本质上是 JavaScript 普通对象。我们约定,action 内必须使用一个字符串类型的 type 字段来表示将要执行的动作。多数情况下,type 会被定义成字符串常量。当应用规模越来越大时,建议使用单独的模块或文件来存放 action。
1.2.3.2 store
- Store 就是把它们联系到一起的对象。Store 有以下职责:
- 维持应用的 state;
- 提供
getState()
方法获取 state; - 提供
dispatch(action)
方法更新 state; - 通过
subscribe(listener)
注册监听器; - 通过
subscribe(listener) 返回的函数
注销监听器。
- 强调一下 Redux 应用只有一个单一的 store。当需要拆分数据处理逻辑时,你应该使用 reducer 组合 而不是创建多个 store。
1.2.3.3 reducer
- Reducers 指定了应用状态的变化如何响应 actions 并发送到 store 的,记住 actions 只是描述了有事情发生了这一事实,并没有描述应用如何更新 state。
- reducer 就是一个纯函数,接收旧的 state 和 action,返回新的 state。
- 整个应用只有一个单一的 reducer 函数:这个函数是传给 createStore 的第一个参数。一个单一的 reducer 最终需要做以下几件事:
- reducer 第一次被调用的时候,state 的值是 undefined。reducer 需要在 action 传入之前提供一个默认的 state 来处理这种情况。
- reducer 需要先前的 state 和 dispatch 的 action 来决定需要做什么事。
- 假设需要更改数据,应该用更新后的数据创建新的对象或数组并返回它们。
- 如果没有什么更改,应该返回当前存在的 state 本身。
1.3 安装redux
- 命令如下:
npm install --save redux
2. redux入门例子
- 直接从官网拷贝的例子,例子地址:
https://www.redux.org.cn/. - 例子如下:
import { createStore } from 'redux';/*** 这是一个 reducer,形式为 (state, action) => state 的纯函数。* 描述了 action 如何把 state 转变成下一个 state。** state 的形式取决于你,可以是基本类型、数组、对象、* 甚至是 Immutable.js 生成的数据结构。惟一的要点是* 当 state 变化时需要返回全新的对象,而不是修改传入的参数。** 下面例子使用 `switch` 语句和字符串来做判断,但你可以写帮助类(helper)* 根据不同的约定(如方法映射)来判断,只要适用你的项目即可。*/ function counter(state = 0, action) {switch (action.type) {case 'INCREMENT':return state + 1;case 'DECREMENT':return state - 1;default:return state;} }// 创建 Redux store 来存放应用的状态。 // API 是 { subscribe, dispatch, getState }。 let store = createStore(counter);// 可以手动订阅更新,也可以事件绑定到视图层。 store.subscribe(() =>console.log(store.getState()) );// 改变内部 state 惟一方法是 dispatch 一个 action。 // action 可以被序列化,用日记记录和储存下来,后期还可以以回放的方式执行 store.dispatch({ type: 'INCREMENT' });// 1 store.dispatch({ type: 'INCREMENT' });// 2 store.dispatch({ type: 'DECREMENT' });// 1
- 效果如下:
3. redux入门例子——优化1(reducer 和 store拆开)
3.1 想要实现的效果
-
因为上面的简单例子中的state没有在页面上渲染,所以简单优化一下,实现页面渲染操作,想呈现的效果如下:
-
如果用纯react写的话,很简单,代码如下:
import { useState } from "react";function CountNum(){const [count,setCount] = useState(0);function add(){setCount(count => count+1);}function subtract(){setCount(count => count-1);}return(<div>当前数字是:{count}<br /><br /><button onClick={add}>点我 +1</button> <br /><br /><button onClick={subtract}>点我 -1</button></div>) } export default CountNum;
-
但我们目的是用redux实现,所以继续……
3.2 代码设计
- 项目结构,如下:
- store.js 和 countReducer.js 如下:
- CountNumRedux.jsx 组件如下:
- 看效果,有问题
怎么重新渲染?继续……
3.3 添加 重新渲染
-
使用
useEffect
进行重新渲染,核心代码如下:useEffect(()=>{store.subscribe(()=>{console.log('订阅更新,打印2-----',store.getState());setCount(store.getState());}); });
-
然后再看效果:
-
关于useEffect ,可以看下面的文章:
React中组件通信02——消息订阅与发布、取消订阅以及卸载组件时取消订阅.
3.4 附代码
-
countReducer.js
/*** 这是一个 reducer,形式为 (state, action) => state 的纯函数。* 描述了 action 如何把 state 转变成下一个 state。** state 的形式取决于你,可以是基本类型、数组、对象、* 甚至是 Immutable.js 生成的数据结构。惟一的要点是* 当 state 变化时需要返回全新的对象,而不是修改传入的参数。** 下面例子使用 `switch` 语句和字符串来做判断,但你可以写帮助类(helper)* 根据不同的约定(如方法映射)来判断,只要适用你的项目即可。*/function countReducer(state = 0,action){console.log(`state:${state}---action:${action}---type:${action.type}`);switch (action.type){case 'INCREMENT':return state + 1;case 'DECREMENT':return state - 1;default:return state;} } export default countReducer;
-
store.js
import { createStore } from 'redux';import countReducer from './countReducer.js'const store = createStore(countReducer);export default store;
-
CountNumRedux.jsx
import { useState,useEffect } from "react"; import store from '../redux/store'function CountNumRedux(){const [count,setCount] = useState(0);function add(){// setCount(count => count+1);//派发action 改变内部 state 惟一方法是 dispatch 一个 action。store.dispatch({ type: 'INCREMENT' });}function subtract(){// setCount(count => count-1);store.dispatch({ type: 'DECREMENT' });}// 可以手动订阅更新,也可以事件绑定到视图层。// store.subscribe(() =>// console.log('订阅更新,打印1-----',store.getState())// );useEffect(()=>{store.subscribe(()=>{console.log('订阅更新,打印2-----',store.getState());setCount(store.getState());});});return(<div>当前数字是:{count} 当前数字是:{store.getState()} <br /><br /><button onClick={add}>点我 +1</button> <br /><br /><button onClick={subtract}>点我 -1</button></div>) }export default CountNumRedux;
4. redux入门例子——优化2(拆出action)
4.1 关于action的其他说明
- 看官网怎么说:
- Action 本质上是 JavaScript 普通对象。我们约定,action 内必须使用一个字符串类型的 type 字段来表示将要执行的动作。多数情况下,type 会被定义成字符串常量。当应用规模越来越大时,建议使用单独的模块或文件来存放 action。
- 除了 type 字段外,action 对象的结构完全由你自己决定。比如下面的:
更多参考可看:https://github.com/redux-utilities/flux-standard-action.{type: ADD_TODO,text: 'Build my first Redux app'}{type: TOGGLE_TODO,index: 5}
- 在 Redux 中的 action 创建函数只是简单的返回一个 action。如下:
4.2 优化——拆出action
- 根据官网上说的,做个简单优化,改动点如下:
效果就不展示了,因为这个还能继续优化,如下……
4.3 优化——动态加减数字
4.3.1 优化看效果
- 如下:
- 效果如下:
4.3.2 附代码
-
代码在上面基础上做了简单的调整,action的type抽出了变量,直接给代码了,如下:
-
countConst.js
//定义常量export const INCREMENT = 'INCREMENT'; //加 export const DECREMENT = 'DECREMENT'; //减
-
countAction.js
// //加的时候 // function incrementNum(){ // return { type: 'INCREMENT' }; // }// //减的时候 // function decrementNum(){ // return { type: 'DECREMENT' }; // }import {INCREMENT,DECREMENT} from './countConst.js'//加的时候 function incrementNum(number){return { type: INCREMENT,number:number }; }//减的时候 function decrementNum(number){return { type: DECREMENT,number:number }; }export default{incrementNum,decrementNum}
-
CountNumRedux.jsx
import { useState,useEffect,useRef, createRef } from "react"; import store from '../redux/store' import countAction from '../redux/countAction'function CountNumRedux(){const [count,setCount] = useState(0);const numberRef = createRef();function add(){// setCount(count => count+1);//派发action 改变内部 state 惟一方法是 dispatch 一个 action。// store.dispatch({ type: 'INCREMENT' });// store.dispatch(countAction.incrementNum());// console.log(numberRef.current.value);let number = numberRef.current.value;// console.log(typeof number); //stringstore.dispatch(countAction.incrementNum(parseInt(number)));}function subtract(){let number = parseInt(numberRef.current.value);store.dispatch(countAction.decrementNum(number));}useEffect(()=>{store.subscribe(()=>{console.log('订阅更新,打印2-----',store.getState());setCount(store.getState());});});return(<div>当前数字是:{count} 当前数字是:{store.getState()} <br />浮动数字:<input type="number" ref={numberRef}/><br /><br /><button onClick={add}>点我 加数</button> <br /><br /><button onClick={subtract}>点我 减数</button></div>) }export default CountNumRedux;
-
countReducer.js
import {INCREMENT,DECREMENT} from './countConst.js'function countReducer(state = 0,action){console.log(`state:${state}---action:${action}---type:${action.type}---number${action.number}`);switch (action.type){case INCREMENT:// return state + 1;return state + action.number;case DECREMENT:// return state - 1;return state - action.number;default:return state;} } export default countReducer;
相关文章:

React(react18)中组件通信04——redux入门
React(react18)中组件通信04——redux入门 1. 前言1.1 React中组件通信的其他方式1.2 介绍redux1.2.1 参考官网1.2.2 redux原理图1.2.3 redux基础介绍1.2.3.1 action1.2.3.2 store1.2.3.3 reducer 1.3 安装redux 2. redux入门例子3. redux入门例子——优…...

最新AI创作系统+ChatGPT网站源码+支持GPT4.0+支持ai绘画+支持国内全AI模型
一、AI创作系统 SparkAi系统是基于很火的GPT提问进行开发的Ai智能问答系统。本期针对源码系统整体测试下来非常完美,可以说SparkAi是目前国内一款的ChatGPT对接OpenAI软件系统。那么如何搭建部署AI创作ChatGPT系统?小编这里写一个详细图文教程吧&#x…...
react+umi项目中引入antd组件报错:“Button”不能用作 JSX 组件解决方案
具体报错信息 “Button”不能用作 JSX 组件。 Its type ‘(props: IProps) > React.ReactElement’ is not a valid JSX element type. 不能将类型“(props: IProps) > React.ReactElement”分配给类型“(props: any, deprecatedLegacyContext?: any) > ReactNode”。…...
常用算法模板
目录 快读、快输 快读、快输 #include <cstdio> #define Re register int #define LD double// 读整数 inline void in(Re &x) {int f 0; x 0; char c getchar();while (c < 0 || c > 9) f | c -, c getchar();while (c > 0 && c < 9) x …...

最全跨境独立站建站详细步骤解析
对于跨境电商卖家来说,无论是规避“鸡蛋放在同一个篮子里”的风险,还是追求更多的销售额和利润,多平台、多站点的布局都是其至关重要的战略。加之市场的变化带来了新的发展机遇,这也使得如今很多出海企业都在抢占独立站新风口。然…...

提升群辉AudioStation音乐体验,实现公网音乐播放
文章目录 本教程解决的问题是:按照本教程方法操作后,达到的效果是本教程使用环境:1 群晖系统安装audiostation套件2 下载移动端app3 内网穿透,映射至公网 很多老铁想在上班路上听点喜欢的歌或者相声解解闷儿,于是打开手…...

虹科分享 | 谷歌Vertex AI平台使用Redis搭建大语言模型
文章来源:虹科云科技 点此阅读原文 基础模型和高性能数据层这两个基本组件始终是创建高效、可扩展语言模型应用的关键,利用Redis搭建大语言模型,能够实现高效可扩展的语义搜索、检索增强生成、LLM 缓存机制、LLM记忆和持久化。有Redis加持的大…...
VS Code 代码跳转到定义(.js 和 .vue文件跳转)
vscode 代码跳转到定义(.js 和 .vue文件跳转) 在日常的开发工作中,我们经常需要跳转到方法或变量的定义处,以便更好地理解和修改代码。VS Code 是目前比较流行的开发工具,然而它默认情况下并不支持这个功能,…...

华为云云耀云服务器L实例评测 | Docker 部署 Reids容器
文章目录 一、使用Docker部署的好处二、Docker 与 Kubernetes 对比三、云耀云服务器L实例 Docker 部署 Redis四、可视化工具连接Redis⛵小结 一、使用Docker部署的好处 Docker的好处在于:在不同实例上运行相同的容器 Docker的五大优点: 持续部署与测试…...

聚观早报 | 杭州亚运开幕科技感拉满;腾讯官宣启动「青云计划」
【聚观365】9月25日消息 杭州亚运开幕科技感拉满 腾讯官宣启动「青云计划」 FF任命新全球CEO 比亚迪夺得多国销冠 iPhone 15/15 Pro销售低于预期 杭州亚运开幕科技感拉满 杭州第19届亚洲运动会开幕式23日晚在杭州奥体中心主体育馆举行,这届开幕式可谓科技感拉…...
Linux Gnome桌面无法打开终端Terminal
文章目录 前言排障解决方式一解决方式二 前言 由于不知名的原因,导致gonme桌面里打开terminal一直转圈,无法打开。 这里我的故障是已知的,我是因为要把英文改为中文。但是界面依旧是英文,同时导致终端无法打开。 此方式centos d…...

MySQL学习笔记15
1、内连接查询(重点): 基本语法: select 数据表1.字段列表,数据表2.字段列表 from 数据表1 inner join 数据表2 on 连接条件; 案例:获取产品表中每个产品的分类信息: mysql> select * from tb_goods …...

6、SpringBoot_项目的打包与运行
七、SpringBoot项目的打包与运行 1.目前项目怎么运行的 通过浏览器访问idea 将jar部署到服务器 2.maven 打包项目 命令 mvn package使用命令后会得到如下的jar 3.程序运行 命令 java -jar 项目.jar启动如下 4.springboot打包需要插件 插件 <plugin><group…...

图像语义分割概述
图像语义分割概述 一、图像语义分割概念 图像语义分割(Image Semantic Segmentation)是一项计算机视觉任务,其目标是将输入的图像分割成多个区域,并为每个像素分配一个语义类别标签,以表示该像素属于图像中的哪个物体…...

ViT细节与代码解读
最近看到两篇解读ViT很好的文章,备忘记录一下: 先理解细节 1:再读VIT,还有多少细节是你不知道的 再理解代码 1:ViT源码阅读-PyTorch - 知乎...
Linux中软链接与硬链接的作用、区别、创建、删除
1、软链接与硬链接的作用 (1)软链接 软链接是Linux中常用的命令,它的功能是某一文件在另外一个位置建立一个同步的链接,相当于C语言中的指针,建立的链接直接指向源文件所在的地址,软链接不会另外占用资源,当同一文件需要在多个位置被用到的时候,就会使用到软连接。 …...
第一章:最新版零基础学习 PYTHON 教程(第十四节 - Python 条件和循环语句–Python 中的 with 语句)
在Python中,with语句用于异常处理,使代码更简洁、更具可读性。它简化了文件流等公共资源的管理。观察以下代码示例,了解使用 with 语句如何使代码更简洁。 Python3 # 文件处理# 1) 不使用with语句 file = open(文件路径, w) # 打开文件以进行写操作 file.write(你好,世界…...

安科瑞AMC16-DETT铁塔jizhan直流电能计量模块,直流计量用
安科瑞虞佳豪壹捌柒陆壹伍玖玖零玖叁 9月20日,在杭州亚运会火炬传递的现场,不少人通过网络与亲友连线,共同见证火炬传递的历史时刻。上午6时,杭州铁塔的一线通信保障人员共27人就已经在本次火炬传递收官点位奥体中心西广场附近&a…...
WebGL笔记:WebGL中JS与GLSL ES 语言通信,着色器间的数据传输示例:js控制绘制点位
js改变点位,动态传值 <canvas id"canvas"></canvas><!-- 顶点着色器 --><script id"vertexShader" type"x-shader/x-vertex">attribute vec4 a_Position;void main() {// 点位gl_Position a_Position;// 尺…...

一文读懂 Redis 缓存系统
【摘要】本文介绍了Redis缓存原理、详细解析了缓存模型、缓存一致性和缓存异常场景。 【作者】李杰,专注于Java虚拟机技术、云原生技术领域的探索与研究。 尽管(关系型)数据库系统 (SQL) 带来了许多出色的属性,例如 ACID&#x…...
Cursor实现用excel数据填充word模版的方法
cursor主页:https://www.cursor.com/ 任务目标:把excel格式的数据里的单元格,按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例,…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一)
宇树机器人多姿态起立控制强化学习框架论文解析 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一) 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化…...
WEB3全栈开发——面试专业技能点P2智能合约开发(Solidity)
一、Solidity合约开发 下面是 Solidity 合约开发 的概念、代码示例及讲解,适合用作学习或写简历项目背景说明。 🧠 一、概念简介:Solidity 合约开发 Solidity 是一种专门为 以太坊(Ethereum)平台编写智能合约的高级编…...

IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)
文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...
高防服务器能够抵御哪些网络攻击呢?
高防服务器作为一种有着高度防御能力的服务器,可以帮助网站应对分布式拒绝服务攻击,有效识别和清理一些恶意的网络流量,为用户提供安全且稳定的网络环境,那么,高防服务器一般都可以抵御哪些网络攻击呢?下面…...
【C++从零实现Json-Rpc框架】第六弹 —— 服务端模块划分
一、项目背景回顾 前五弹完成了Json-Rpc协议解析、请求处理、客户端调用等基础模块搭建。 本弹重点聚焦于服务端的模块划分与架构设计,提升代码结构的可维护性与扩展性。 二、服务端模块设计目标 高内聚低耦合:各模块职责清晰,便于独立开发…...

CVE-2020-17519源码分析与漏洞复现(Flink 任意文件读取)
漏洞概览 漏洞名称:Apache Flink REST API 任意文件读取漏洞CVE编号:CVE-2020-17519CVSS评分:7.5影响版本:Apache Flink 1.11.0、1.11.1、1.11.2修复版本:≥ 1.11.3 或 ≥ 1.12.0漏洞类型:路径遍历&#x…...

算法:模拟
1.替换所有的问号 1576. 替换所有的问号 - 力扣(LeetCode) 遍历字符串:通过外层循环逐一检查每个字符。遇到 ? 时处理: 内层循环遍历小写字母(a 到 z)。对每个字母检查是否满足: 与…...

【从零学习JVM|第三篇】类的生命周期(高频面试题)
前言: 在Java编程中,类的生命周期是指类从被加载到内存中开始,到被卸载出内存为止的整个过程。了解类的生命周期对于理解Java程序的运行机制以及性能优化非常重要。本文会深入探寻类的生命周期,让读者对此有深刻印象。 目录 …...
比较数据迁移后MySQL数据库和OceanBase数据仓库中的表
设计一个MySQL数据库和OceanBase数据仓库的表数据比较的详细程序流程,两张表是相同的结构,都有整型主键id字段,需要每次从数据库分批取得2000条数据,用于比较,比较操作的同时可以再取2000条数据,等上一次比较完成之后,开始比较,直到比较完所有的数据。比较操作需要比较…...