当前位置: 首页 > news >正文

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 中的数据,你需要发起一个 actionAction 就是一个普通 JavaScript 对象(注意到没,这儿没有任何魔法?)用来描述发生了什么。
    • 强制使用 action 来描述所有变化带来的好处是可以清晰地知道应用中到底发生了什么。如果一些东西改变了,就可以知道为什么变。action 就像是描述发生了什么的指示器。
    • 最终,为了把 action 和 state 串起来,开发一些函数,这就是 reducer。再次地强调,没有任何魔法,reducer 只是一个接收 state 和 action,并返回新的 state 的函数,并且是一个纯函数
    • 而整个应用的 state 被储存在一棵 object tree 中,并且这个 object tree 只存在于唯一一个 store 中。

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}    &nbsp;&nbsp;&nbsp;&nbsp;当前数字是:{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 对象的结构完全由你自己决定。比如下面的:
      	{type: ADD_TODO,text: 'Build my first Redux app'}{type: TOGGLE_TODO,index: 5}
      
      更多参考可看:https://github.com/redux-utilities/flux-standard-action.
    • 在 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}    &nbsp;&nbsp;&nbsp;&nbsp;当前数字是:{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&#xff08;react18&#xff09;中组件通信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智能问答系统。本期针对源码系统整体测试下来非常完美&#xff0c;可以说SparkAi是目前国内一款的ChatGPT对接OpenAI软件系统。那么如何搭建部署AI创作ChatGPT系统&#xff1f;小编这里写一个详细图文教程吧&#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 …...

最全跨境独立站建站详细步骤解析

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

提升群辉AudioStation音乐体验,实现公网音乐播放

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

虹科分享 | 谷歌Vertex AI平台使用Redis搭建大语言模型

文章来源&#xff1a;虹科云科技 点此阅读原文 基础模型和高性能数据层这两个基本组件始终是创建高效、可扩展语言模型应用的关键&#xff0c;利用Redis搭建大语言模型&#xff0c;能够实现高效可扩展的语义搜索、检索增强生成、LLM 缓存机制、LLM记忆和持久化。有Redis加持的大…...

VS Code 代码跳转到定义(.js 和 .vue文件跳转)

vscode 代码跳转到定义&#xff08;.js 和 .vue文件跳转&#xff09; 在日常的开发工作中&#xff0c;我们经常需要跳转到方法或变量的定义处&#xff0c;以便更好地理解和修改代码。VS Code 是目前比较流行的开发工具&#xff0c;然而它默认情况下并不支持这个功能&#xff0c…...

华为云云耀云服务器L实例评测 | Docker 部署 Reids容器

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

聚观早报 | 杭州亚运开幕科技感拉满;腾讯官宣启动「青云计划」

【聚观365】9月25日消息 杭州亚运开幕科技感拉满 腾讯官宣启动「青云计划」 FF任命新全球CEO 比亚迪夺得多国销冠 iPhone 15/15 Pro销售低于预期 杭州亚运开幕科技感拉满 杭州第19届亚洲运动会开幕式23日晚在杭州奥体中心主体育馆举行&#xff0c;这届开幕式可谓科技感拉…...

Linux Gnome桌面无法打开终端Terminal

文章目录 前言排障解决方式一解决方式二 前言 由于不知名的原因&#xff0c;导致gonme桌面里打开terminal一直转圈&#xff0c;无法打开。 这里我的故障是已知的&#xff0c;我是因为要把英文改为中文。但是界面依旧是英文&#xff0c;同时导致终端无法打开。 此方式centos d…...

MySQL学习笔记15

1、内连接查询&#xff08;重点&#xff09;&#xff1a; 基本语法&#xff1a; select 数据表1.字段列表,数据表2.字段列表 from 数据表1 inner join 数据表2 on 连接条件; 案例&#xff1a;获取产品表中每个产品的分类信息&#xff1a; mysql> select * from tb_goods …...

6、SpringBoot_项目的打包与运行

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

图像语义分割概述

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

ViT细节与代码解读

最近看到两篇解读ViT很好的文章&#xff0c;备忘记录一下&#xff1a; 先理解细节 1&#xff1a;再读VIT&#xff0c;还有多少细节是你不知道的 再理解代码 1&#xff1a;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日&#xff0c;在杭州亚运会火炬传递的现场&#xff0c;不少人通过网络与亲友连线&#xff0c;共同见证火炬传递的历史时刻。上午6时&#xff0c;杭州铁塔的一线通信保障人员共27人就已经在本次火炬传递收官点位奥体中心西广场附近&a…...

WebGL笔记:WebGL中JS与GLSL ES 语言通信,着色器间的数据传输示例:js控制绘制点位

js改变点位&#xff0c;动态传值 <canvas id"canvas"></canvas><!-- 顶点着色器 --><script id"vertexShader" type"x-shader/x-vertex">attribute vec4 a_Position;void main() {// 点位gl_Position a_Position;// 尺…...

一文读懂 Redis 缓存系统

【摘要】本文介绍了Redis缓存原理、详细解析了缓存模型、缓存一致性和缓存异常场景。 【作者】李杰&#xff0c;专注于Java虚拟机技术、云原生技术领域的探索与研究。 尽管&#xff08;关系型&#xff09;数据库系统 (SQL) 带来了许多出色的属性&#xff0c;例如 ACID&#x…...

边缘计算医疗风险自查APP开发方案

核心目标:在便携设备(智能手表/家用检测仪)部署轻量化疾病预测模型,实现低延迟、隐私安全的实时健康风险评估。 一、技术架构设计 #mermaid-svg-iuNaeeLK2YoFKfao {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg…...

苍穹外卖--缓存菜品

1.问题说明 用户端小程序展示的菜品数据都是通过查询数据库获得&#xff0c;如果用户端访问量比较大&#xff0c;数据库访问压力随之增大 2.实现思路 通过Redis来缓存菜品数据&#xff0c;减少数据库查询操作。 缓存逻辑分析&#xff1a; ①每个分类下的菜品保持一份缓存数据…...

学习STC51单片机31(芯片为STC89C52RCRC)OLED显示屏1

每日一言 生活的美好&#xff0c;总是藏在那些你咬牙坚持的日子里。 硬件&#xff1a;OLED 以后要用到OLED的时候找到这个文件 OLED的设备地址 SSD1306"SSD" 是品牌缩写&#xff0c;"1306" 是产品编号。 驱动 OLED 屏幕的 IIC 总线数据传输格式 示意图 …...

css的定位(position)详解:相对定位 绝对定位 固定定位

在 CSS 中&#xff0c;元素的定位通过 position 属性控制&#xff0c;共有 5 种定位模式&#xff1a;static&#xff08;静态定位&#xff09;、relative&#xff08;相对定位&#xff09;、absolute&#xff08;绝对定位&#xff09;、fixed&#xff08;固定定位&#xff09;和…...

leetcodeSQL解题:3564. 季节性销售分析

leetcodeSQL解题&#xff1a;3564. 季节性销售分析 题目&#xff1a; 表&#xff1a;sales ---------------------- | Column Name | Type | ---------------------- | sale_id | int | | product_id | int | | sale_date | date | | quantity | int | | price | decimal | -…...

OpenLayers 分屏对比(地图联动)

注&#xff1a;当前使用的是 ol 5.3.0 版本&#xff0c;天地图使用的key请到天地图官网申请&#xff0c;并替换为自己的key 地图分屏对比在WebGIS开发中是很常见的功能&#xff0c;和卷帘图层不一样的是&#xff0c;分屏对比是在各个地图中添加相同或者不同的图层进行对比查看。…...

力扣-35.搜索插入位置

题目描述 给定一个排序数组和一个目标值&#xff0c;在数组中找到目标值&#xff0c;并返回其索引。如果目标值不存在于数组中&#xff0c;返回它将会被按顺序插入的位置。 请必须使用时间复杂度为 O(log n) 的算法。 class Solution {public int searchInsert(int[] nums, …...

JAVA后端开发——多租户

数据隔离是多租户系统中的核心概念&#xff0c;确保一个租户&#xff08;在这个系统中可能是一个公司或一个独立的客户&#xff09;的数据对其他租户是不可见的。在 RuoYi 框架&#xff08;您当前项目所使用的基础框架&#xff09;中&#xff0c;这通常是通过在数据表中增加一个…...

Linux 中如何提取压缩文件 ?

Linux 是一种流行的开源操作系统&#xff0c;它提供了许多工具来管理、压缩和解压缩文件。压缩文件有助于节省存储空间&#xff0c;使数据传输更快。本指南将向您展示如何在 Linux 中提取不同类型的压缩文件。 1. Unpacking ZIP Files ZIP 文件是非常常见的&#xff0c;要在 …...

MySQL:分区的基本使用

目录 一、什么是分区二、有什么作用三、分类四、创建分区五、删除分区 一、什么是分区 MySQL 分区&#xff08;Partitioning&#xff09;是一种将单张表的数据逻辑上拆分成多个物理部分的技术。这些物理部分&#xff08;分区&#xff09;可以独立存储、管理和优化&#xff0c;…...