第三十三章 使用Redux管理状态

news/2024/5/16 10:27:59/文章来源:https://blog.csdn.net/qq_36362721/article/details/130727389

  Redux(全称为Redux)是一个基于状态管理的JavaScript库,它可以用来构建可重用的、可维护的代码。Redux主要用于处理复杂的应用程序中的状态管理,它能够自动地处理应用程序中的更改,并在需要时更新视图。

  Redux使用一种被称为“状态树”的数据结构来管理应用程序的状态。状态树中的每个节点都代表应用程序中的一个状态,而每个状态都可以有自己的副本和父节点。当应用程序中的某个状态发生更改时,它会通过一个被称为“动作”的API来更新状态树,并触发有关的副作用。这意味着,当一个部分的状态更改时,不会影响其他部分。

  Redux使用一个中央控制器来协调应用程序中的所有状态更改。这个控制器可以监听所有的动作,并根据需要更改状态。Redux也提供了一些工具,如树形状态视图和状态转换器,来帮助开发人员处理复杂的状态管理。

  总的来说,Redux是一种非常强大和灵活的库,可以用来构建复杂的应用程序。它能够使开发人员专注于应用程序的逻辑,并帮助他们更轻松地管理应用程序中的状态。

具体详情请参考:Redux 中文官网


什么情况下使用Redux?

Redux 通常用于处理复杂的应用程序,特别是那些具有大量状态和复杂逻辑的应用程序。以下是一些 Redux 可能适合您的应用程序的示例:

  • 您的应用程序具有复杂的路由和状态管理逻辑。
  • 您需要处理大量的状态和更改,并且不希望在代码中硬编码它们。
  • 您需要更好地组织和管理您的状态和副作用。
  • 您需要一种方式来组合和重用不同的状态和动作。

当您考虑使用 Redux 时,需要确定您的应用程序是否适合使用 Redux。如果您的应用程序符合上述条件,那么 ReducerMiddlewareother 组件可以帮助您更轻松地管理应用程序的状态和逻辑。


Redux的工作原理

Redux 的工作原理是通过将应用程序的状态和动作拆分成独立的组件来实现的。在 Reducer 中,您可以使用一组函数来更改应用程序的状态。每个函数都接收一个 state 和一个 action,并返回一个新的 stateRedux 通过组合这些 state 来控制应用程序的状态。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HeKPRhDI-1684308971073)(D:\GeniusNotes\ReactNote\react_staging\img\redux原理图.png)]

Redux 中,还有一些中间件(称为 Connect),它们用于协调 Redux 中的组件。Connect 可以帮助您将应用程序的不同部分连接在一起,并提供一些功能,如数据流和状态管理。 当 Redux 中的某个组件触发一个动作时,它会通过 Action 来通知 Redux。这个 Action 可以被 Redux 中的其他组件所读取和处理。Redux 还提供了一些其他的工具和库,如 ConnectHooks Reducer,来帮助开发人员处理复杂的应用程序逻辑。

Redux的三个核心概念

  1. ActionAction 是一种数据类型,它表示一个状态更改操作。Action 可以被 Redux 中的所有组件读取和处理。Action 可以包含任何类型的数据,例如字符串、数字或映射。
  2. ReducerReducerRedux 中用于修改 state 的组件。Reducer 接收一个 state 和一个 action,并返回一个 new stateReducer 的作用是通过更改状态来控制 Redux 中的应用程序逻辑。Reducer 通常由一组函数组成,这些函数接收一个 state 和一个 action,并返回一个 new state
  3. StoreStoreRedux 中用于存储和管理 state 和动作的组件。Store 是一个全局的对象,它可以存储应用程序的所有 state 和动作。Store 可以被 Redux 中的其他组件所读取和处理。Store 还负责协调 Redux 中的所有 state 的更改。

通过求和案例循序渐进了解Redux

以下是案列的图示:

在这里插入图片描述

该组件(包含一个下拉框,四个功能按钮)功能很简单:

  • 选择下拉框,选择要加减的具体数值
  • 点击按钮+,将下拉框的数值进行相加
  • 点击按钮-,将下拉框的数值进行相减
  • 点击按钮当前求和为奇数为,当和是奇数的时候才将下拉框的值进行相加,否则不操作
  • 点击按钮异步加,点击按钮之后,隔一段时间才将下拉框的值进行相加

1、使用普通的react程序实现该功能

文件:components/Count/index.jsx

import React, { Component } from 'react'export default class Count extends Component {state = { count: 0 }increment = () => {// 普通加// 1、获取用户选择的值const { value } = this.selectNumber// 2、获取原来状态里面的值const { count } = this.state// 3、进行计算并更新状态值this.setState({ count: count + value * 1 })}decrement = () => {// 普通减// 1、获取用户选择的值const { value } = this.selectNumber// 2、获取原来状态里面的值const { count } = this.state// 3、进行计算并更新状态值this.setState({ count: count - value * 1 })}incrementIfOdd = () => {// 当前求和为奇数为// 1、获取用户选择的值const { value } = this.selectNumber// 2、获取原来状态里面的值const { count } = this.state// 3、进行计算并更新状态值if (store.getState() % 2 !== 0) {this.setState({ count: count + value * 1 })}}incrementAsync = () => {// 异步加// 1、获取用户选择的值const { value } = this.selectNumber// 2、获取原来状态里面的值const { count } = this.state// 3、进行计算并更新状态值setTimeout(() => {this.setState({ count: count + value * 1 })}, 500)}render() {return (<div><h1>当前求和为:{this.state.count}</h1><select ref={(c) => (this.selectNumber = c)}><option value="1">1</option><option value="2">2</option><option value="3">3</option></select>&nbsp;<button onClick={this.increment}>+</button>&nbsp;<button onClick={this.decrement}>-</button>&nbsp;<button onClick={this.incrementIfOdd}>当前求和为奇数为</button>&nbsp;<button onClick={this.incrementAsync}>异步加</button>&nbsp;</div>)}
}

文件:App.jsx

import React, { Component } from 'react'
import Count from './components/Count'export default class App extends Component {render() {return (<div><Count/></div>)}
}

以上代码就是通过普通的state实现的案例功能。


2、Redux精简版改进求和案例

  • 步骤1:安装依赖包
npm i redux
  • 步骤2:创建文件:redux/store.js
/** 该文件专门用于暴露store对象,整个应用只有一个store对象 */
// 引入createStore,专门用于创建redux中最为核心的store对象
import { createStore } from 'redux'
// 引入为Count组件服务的reducer
import countReducer from './count_reducer'
// 暴露store
export default createStore(countReducer)
  • 步骤3:创建文件:redux/count_reducer.js
/*** 1、该文件是用于创建一个为count组件服务的reducer,reducer的本质就是一个函数* 2、reducer函数会接到两个参数,分别为:之前的状态(preState),动作对象(action)*/
const initCount = 0  // 当reducer做初始化的时候,将初始值undefined改为0
export default function countReducer( preState = initCount, action) {// 从action对象中获取type和dataconst { type, data } = action;// 根据type类型,如何加工数据switch (type) {case 'increment': // 如果是加,使用以下逻辑加工数据return preState + data;case 'decrement': // 如果是减,使用以下逻辑加工数据return preState - data;default:return preState ;}
}
  • 步骤4:修改Count组件逻辑
import React, { Component } from 'react'
import store from '../../redux/store' // 引入storeexport default class Count extends Component {// state = { count: 0 } // 使用了redux的状态后,就不需要组件内部的state了componentDidMount() {// 监测redux中状态的变化,只要变化,就调用renderstore.subscribe(()=>{this.setState({}) // 当调用这个方法后,页面才会更新})}increment = () => {// 普通加// 1、获取用户选择的值const { value } = this.selectNumber// 2、进行计算并更新状态值,通知redux执行相加逻辑store.dispatch({type:'increment',data: value * 1})}decrement = () => {// 普通减// 1、获取用户选择的值const { value } = this.selectNumber// 2、进行计算并更新状态值,通知redux执行相减逻辑store.dispatch({type:'decrement',data: value * 1})}incrementIfOdd = () => {// 当前求和为奇数为// 1、获取用户选择的值const { value } = this.selectNumber// 2、进行计算并更新状态值if (store.getState() % 2 !== 0) {// 通知redux执行相加逻辑store.dispatch({type:'increment',data: value * 1})}}incrementAsync = () => {// 异步加// 1、获取用户选择的值const { value } = this.selectNumber// 2、进行计算并更新状态值setTimeout(() => {// 通知redux执行相加逻辑store.dispatch({type:'increment',data: value * 1})}, 500)}render() {// store.getState(),这个API用于获取redux的状态return (<div><h1>当前求和为:{store.getState()}</h1><select ref={(c) => (this.selectNumber = c)}><option value="1">1</option><option value="2">2</option><option value="3">3</option></select>&nbsp;<button onClick={this.increment}>+</button>&nbsp;<button onClick={this.decrement}>-</button>&nbsp;<button onClick={this.incrementIfOdd}>当前求和为奇数为</button>&nbsp;<button onClick={this.incrementAsync}>异步加</button>&nbsp;</div>)}
}
  • 步骤5:优化redux的监听

为了让整个应用都监听redux的变化,我们需要将订阅redux变化的逻辑写到入口文件中

文件:index.js

import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import store from './redux/store'const root = ReactDOM.createRoot(document.getElementById('root'));root.render(<React.StrictMode><App /></React.StrictMode>
);
// 监听全局redux,一但发生改变就会更新页面
store.subscribe(()=> {root.render(<React.StrictMode><App /></React.StrictMode>);
})
  • 小节总结

(1). 去除Count组件自身的状态

(2). src下建立:

-src|----redux|----store.js|----count_reducer.js

(3).store.js:

​ 1).引入redux中的createStore函数,创建一个store

​ 2).createStore调用时需要传入一个为其服务的reducer

​ 3).记得暴露store对象

(4).count_reducer.js:

​ 1). reducer的本质是一个函数,接收:preState,action,返回加工后的状态

​ 2). reducer有两个作用:初始化状态,加工状态

​ 3). reducer被第一次调用时,是store自动触发的,传递的preStateundefined,传递的action是:{type:'@@REDUX/INIT_a.1.2.3'}

(5).在index.js中监测store中状态的改变,一旦发生改变重新渲染<App/>

备注:redux只负责管理状态,至于状态的改变驱动着页面的展示,要靠我们自己写。


3、Redux完整版求和案例

完整版比精简版多了几个文件:constant.jscount_action.js

  • 定义常量文件:constant.js,便于管理
// 该模块是用于定义action对象的type类型的常量值
export const INCREMENT = 'increment'
export const DECREMENT = 'decrement'
  • 定义管理action对象的文件,层次分明
// 该文件专门为Count组件生成action对象
import {INCREMENT,DECREMENT} from './constant'
export const createIncrementAction = data => ({ type: INCREMENT,data})export const createDecrementAction = data => ({ type: DECREMENT,data})
  • 完善组件内容
import React, { Component } from 'react'
import store from '../../redux/store'
// 引入actioncreator,专门用于创建action对象
import { createIncrementAction, createDecrementAction} from '../../redux/count_action'
export default class Count extends Component {increment = () => {// 普通加// 1、获取用户选择的值const { value } = this.selectNumber// 2、进行计算并更新状态值// 通知redux更改状态store.dispatch(createIncrementAction(value * 1))}decrement = () => {// 普通减// 1、获取用户选择的值const { value } = this.selectNumber// 2、进行计算并更新状态值// 通知redux更改状态store.dispatch(createDecrementAction(value * 1))}incrementIfOdd = () => {// 当前求和为奇数为// 1、获取用户选择的值const { value } = this.selectNumber// 2、进行计算并更新状态值if (store.getState() % 2 !== 0) {// 通知redux更改状态store.dispatch(createIncrementAction(value * 1))}}incrementAsync = () => {// 异步加// 1、获取用户选择的值const { value } = this.selectNumber// 2、进行计算并更新状态值setTimeout(() => {// 通知redux更改状态store.dispatch(createIncrementAction(value * 1))}, 500)}render() {return (<div><h1>当前求和为:{store.getState()}</h1><select ref={(c) => (this.selectNumber = c)}><option value="1">1</option><option value="2">2</option><option value="3">3</option></select>&nbsp;<button onClick={this.increment}>+</button>&nbsp;<button onClick={this.decrement}>-</button>&nbsp;<button onClick={this.incrementIfOdd}>当前求和为奇数为</button>&nbsp;<button onClick={this.incrementAsync}>异步加</button>&nbsp;</div>)}
}
  • 小节总结

新增文件:

(1). count_action.js:专门为Count组件服务创建action对象。

(2). constant.js:放置容易写错的type值。


4、Redux中开启异步action

Redux中,同步Action和异步Action的主要区别在于它们如何触发dispatch

同步Action: 当一个同步Action被创建时,它会立即被发送到store中,并等待store更新状态。如果有其他组件正在使用store,那么这些组件也会立即更新状态。因此,同步Action通常用于那些不需要等待的、简单的操作。

异步Action: 异步Action会在发出后继续执行其他操作,直到完成后再将结果发送到store中。这意味着,如果有其他组件正在使用store,那么它们可能不会立即看到更新的状态。因此,异步Action通常用于那些需要等待的操作。

  • 步骤1:编写一个异步的action的函数

普通的action返回的是一个Object的一般对象,而异步action返回的是一个函数,因为只有在函数里面才能进行异步操作。

文件:redux/count_action.js

// 该文件专门为Count组件生成action对象
import {INCREMENT,DECREMENT} from './constant'
// 一般action,返回的是一般对象
export const createIncrementAction = data => ({ type: INCREMENT,data})export const createDecrementAction = data => ({ type: DECREMENT,data})
// 异步action,返回的是一个函数
export const createIncrementAsyncAction = (data,time) => {// 在返回的函数的参数是一个dispatch,用于我们处理完异步任务后分发action对象return (dispatch) => { setTimeout(() => {dispatch(createIncrementAction(data))}, time);}
}
  • 步骤2:引入中间件来支持异步action

由于store分发action的时候,它只认普通对象,如果要接收一个函数就需要使用到一个中间件。

(1). 安装依赖redux-thunk

npm i redux-thunk

(2). 修改redux/store.js文件

// 引入createStore,专门用于创建redux中最为核心的store对象
import { createStore , applyMiddleware} from 'redux'
import countReducer from './count_reducer'// 引入redux-thunk,用于支持异步action
import thunk from 'redux-thunk'
export default createStore(countReducer,applyMiddleware(thunk))
  • 步骤3:在Count组件里面使用异步action
import React, { Component } from 'react'
import store from '../../redux/store'
// 引入actioncreator,专门用于创建action对象
import {  createIncrementAsyncAction} from '../../redux/count_action'
export default class Count extends Component {// ...incrementAsync = () => {// 异步加// 1、获取用户选择的值const { value } = this.selectNumber// 2、进行计算并更新状态值store.dispatch(createIncrementAsyncAction(value*1,500))}render() {return (<div><h1>当前求和为:{store.getState()}</h1><select ref={(c) => (this.selectNumber = c)}><option value="1">1</option><option value="2">2</option><option value="3">3</option></select>&nbsp;<button onClick={this.increment}>+</button>&nbsp;<button onClick={this.decrement}>-</button>&nbsp;<button onClick={this.incrementIfOdd}>当前求和为奇数为</button>&nbsp;<button onClick={this.incrementAsync}>异步加</button>&nbsp;</div>)}
}
  • 小节总结

    (1).明确:延迟的动作不想交给组件自身,想交给action

    (2).何时需要异步action:想要对状态进行操作,但是具体的数据靠异步任务返回

    (3).具体编码:

​ 1). npm i redux-thunk ,并配置在store

​ 2). 创建action的函数不再返回一般对象,而是一个函数,该函数中写异步任务

​ 3). 异步任务有结果后,分发一个同步的action去真正操作数据。

​ 4). 备注:异步任务action不是必须要写的,完全可以自己等待异步任务的结果完了,再去分发同步action

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

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

FreeRTOS_系统配置

目录 1. FreeRTOSConfig.h 文件 2. "INCLUDE_" 开始的宏 2.1 INCLUDE_xSemaphoreGetMutexHolder 2.2 INCLUDE_xTaskAbortDelay 2.3 INCLUDE_vTaskDelay 2.4 INCLUDE_vTaskDelayUntil 2.5 INCLUDE_vTaskDelete 2.6 INCLUDE_xTaskGetCurrentTaskHandle 2.7 IN…

Matlab论文插图绘制模板第92期—折线图(Plot)

之前有分享过Matlab折线图的绘制模板&#xff1a; 但随着技术力的提升&#xff0c;发现很多地方还有待改进&#xff0c;于是便有了本期内容。 先来看一下成品效果&#xff1a; 特别提示&#xff1a;本期内容『数据代码』已上传资源群中&#xff0c;加群的朋友请自行下载。有需…

5th-Generation Mobile Communication Technology(二)

目录 一、5G/NR 1、 快速参考&#xff08;Quick Reference&#xff09; 2、5G Success 3、5G Challenges 4、Qualcomm Videos 二、PHY and Protocol 1、Frame Structure 2、Numerology 3、Waveform 4、Frequency Band 5、BWP 6、Synchronization 7、Beam Management 8、CSI Fra…

FiftyOne 系列教程(2)使用FiftyOne读取数据集

1. 支持的数据集 1.1. 支持各种常见的数据集格式 docs.voxel51.com/user guide/dataset creation/datasets.html#supported import formats此外&#xff0c;zoo上面有什么数据集&#xff0c;这里就可以加载到对应的数据集Available Zoo Datasets — FiftyOne 0.20.1 document…

nacos服务端源码集群同步源码分析

nacos集群状态同步源码分析 ServerStatusReporter ServerStatusReporter 是 ServerListManager的内部类 通过Component注解被解析到spring容器中 再通过PostConstruct初始化执行init方法 上边代码启动了一个延时2秒的线程 private class ServerStatusReporter implements Run…

微软限制我们使用Windows系统了,怎么办?

正如中国工程院院士倪光南所说&#xff0c;操作系统的成功与否&#xff0c;关键在于生态系统&#xff0c;需要搭建起完整的产业链上各个主体共生的生态体系。 当前我国国产操作系统市场发展很快&#xff0c;相比技术和市场突破&#xff0c;真正需要解决的问题是如何把生态建好…

阿里云无影云桌面(使用测评)

阿里云试用链接 https://click.aliyun.com/m/1000371700/ 一&#xff1a;无影云桌面简介&#xff1a; 阿里云无影云桌面是一款基于云计算技术的云桌面解决方案&#xff0c;它可以将用户的个人电脑、笔记本电脑等设备上的操作系统和应用程序等资源转移到云端&#xff0c;并通过…

多表联查及mybatis中@Results,@ResultMap注解的应用

在实际的项目中&#xff0c;为了保证数据的简洁和查询的效率&#xff0c;通常会到采用多表联查。 那么什么是多表联查呢&#xff1f; 一般查询语句都是针对一个表的&#xff0c;但是在关系型数据库中&#xff0c;表与表之间是有联系的&#xff0c;所以在实际应用中&#xff0…

【软件测试】未来软件测试必备的八大技能!你缺少哪个?

软件测试工程师是个神奇的职业&#xff0c;他是开发人员与老板之间的传话筒&#xff08;三夹板&#xff09;&#xff0c;也是开发人员与老板的好帮手&#xff1b; 他不仅需要有销售的沟通能力&#xff0c;也需要具备编辑人员的文档撰写技巧。如此一个面面俱到的岗位&#xff0…

数据在 Mocaverse 项目启动过程中是如何发挥作用的

日期&#xff1a;2023年5月 数据源&#xff1a; Mocaverse Realm Ticket Collection Airdrop & Mocaverse Optimizes an NFT Project at Launch & Beyond NFT 是 Web3 社区的基础。它们是区块链游戏、DAO 和 metaverses 的入场券&#xff0c;以及成为社区参与者的数字…

华为新模拟器eNSPLite下载,部署教程及产品使用文档

华为新模拟器eNSPLite下载&#xff0c;部署教程及产品使用文档 如需下载请到我的博客中下载 硬件要求 数通培训认证模拟器支持在个人PC和物理服务器上部署安装&#xff0c;如下所示。 硬件推荐配置CPUX86_64架构CPU&#xff0c;支持VT-x/AMD-V 8核或以上RAM16G或以上DISK40G以…

计算机基础知识之字符编码

目录 1、基础知识2、ASCII编码3、编码格式4、多字节字符集&#xff08;MBCS&#xff09;和中文字符集5、ANSI 标准、国家标准、 ISO 标准6、Unicode 编码7、 UTF-8编码 1、基础知识 &#x1f449;字符&#xff1a;是各种文字和符号的总称&#xff0c;包括各个国家的文字&#…

开心档之Java 基本数据类型

Java 基本数据类型 目录 Java 基本数据类型 内置数据类型 实例 实例 类型默认值 实例 引用类型 Java 常量 自动类型转换 自动类型转换 实例 强制类型转换 实例 隐含强制类型转换 变量就是申请内存来存储值。也就是说&#xff0c;当创建变量的时候&#xff0c;需…

chat中文国内版软件开发

如果要开发中文国内版的Chat软件&#xff0c;可能会包括以下一些功能&#xff1a; 中文自然语言处理&#xff1a;对于中文文本&#xff0c;需要进行中文自然语言处理&#xff0c;包括分词、词性标注、命名实体识别、情感分析等。 智能问答和对话系统&#xff1a;开发智…

什么是单点登录

一、什么是单点登录&#xff1f; 单点登录的英文名叫做&#xff1a;Single Sign On&#xff08;简称SSO&#xff09;。 在初学/以前的时候&#xff0c;一般我们就单系统&#xff0c;所有的功能都在同一个系统上。 后来&#xff0c;我们为了合理利用资源和降低耦合性&#xff…

张益唐直播报告学术报告,零点猜想问题终于被解决(文末可获取论文原文)

原创 | 文BFT机器人 8日上午9点&#xff0c;张益唐教授带着一支黑笔、一块白板现身b站直播&#xff0c;全网超10万人在线观看&#xff0c;从直播消息放出开始&#xff0c;大家就早早端好了小板凳等着教授精彩开讲&#xff01; 直播40分钟一堂课的时长&#xff0c;知识点一个接…

Java面试知识点(全)-spring面试知识点一

Java面试知识点(全) 导航&#xff1a; https://nanxiang.blog.csdn.net/article/details/130640392 注&#xff1a;随时更新 Spring原理 Spring ioc概念&#xff1a;控制权由对象本身转向容器&#xff1b;由容器根据配置文件去创建实例并创建各个实例之间的依赖关系。核心&am…

python@切片slice对象@sequence@range@arange

文章目录 python文档查阅tipsrangenumpy arangenumpy arangepython range&#x1f388; collections容器的抽象基类eg sequence&#x1f388;python序列类型slice切片slice()内置方法itertools.slice()方法 python切片slicesequencerangearange python文档查阅tips preface:想…

4年开发,还不如2年经验的测试.....

代码码了这么些年&#xff0c;你年薪达到多少了&#xff1f; 我&#xff0c;4年码龄&#xff0c;薪资最高的时候16k*12薪&#xff0c;年薪不到20W。都说IT行业薪资高&#xff0c;但年薪百万的还是金字塔尖极少数&#xff0c;像我这样的才是普通的大多数&#xff0c;却也还要用…

Jvm-08a.类加载器

类与类加载器 对于任意一个类&#xff0c;都必须由加载它的类加载器和这个类本身一起共同确立其在Java虚拟机中的唯一性&#xff0c;每一个类加载器&#xff0c;都拥有一个独立的类名称空间。 通俗的讲就是比较两个类是否"相等"&#xff0c;只有在这两个类是由同一…