React(七):Redux

Redux基本使用

纯函数:1.函数内部不能依赖函数外部变量;2.不能产生副作用,在函数内部改变函数外部的变量

React只帮我们解决了DOM的渲染过程,State还是要由我们自己来管理——redux可帮助我们进行管理

Redux三大特点

1.单一数据源:整个应用的状态存储在一个单一的对象树,且该对象树只存储在一个store中

2.State是只读的:状态是不可直接修改的,必须通过触发一个“action”来发起状态的变更

3.使用纯函数来完成状态变更:通过reducer旧stateactions联系在一起,并返回一个新的state;不产生任何副作用。

Redux测试项目搭建

step1:项目初始化

npm init

step2:安装redux

npm i redux

step3:创建store仓库,并存储数据

const { createStore } = require('redux');
const {reducer} = require('./reducer');// 创建的store
const store = createStore(reducer);module.exports = store;

step4:创建reducer函数

const { ADD_NUMBER, CHANGE_NAME } = require("./constants")// 初始化的数据
const initialState = {name: "why",counter: 100
}function reducer(state = initialState, action) {switch(action.type) {case CHANGE_NAME:return { ...state, name: action.name }case ADD_NUMBER:return { ...state, counter: state.counter + action.num }default:return state}
}module.exports = reducer

注意:在该代码中,我们将action的类型封装到了constants.js文件中,方便复用

const ADD_NUMBER = "add_number"
const CHANGE_NAME = "change_name"module.exports = {ADD_NUMBER,CHANGE_NAME
}

step5:通过action来修改state

将它封装到一个单独的文件中

const { ADD_NUMBER, CHANGE_NAME } = require("./constants")const changeNameAction = (name) => ({type: CHANGE_NAME,name
})const addNumberAction = (num) => ({type: ADD_NUMBER,num
})module.exports = {changeNameAction,addNumberAction
}

然后在使用的组件中进行调用

const store = require("./store")
const { addNumberAction, changeNameAction } = require("./store/actionCreators")const unsubscribe = store.subscribe(() => {console.log("订阅数据的变化:", store.getState())
})// 修改store中的数据: 必须action
store.dispatch(changeNameAction("kobe"))
store.dispatch(changeNameAction("lilei"))
store.dispatch(changeNameAction("james"))unsubscribe()// 修改counter
store.dispatch(addNumberAction(10))
store.dispatch(addNumberAction(20))
store.dispatch(addNumberAction(30))

最终,通过拆分代码我们会形成4个文件:

  1. store/index.js文件
  2. store/reducer.js文件
  3. store/actionCreators.js文件
  4. store/constants.js文件

React中使用Redux

redux使用过程:首先会在一个中心的store里面存储我们对应的状态,然后就可以让一些组件中store中订阅一些数据;然后也可以在组件中通过dispatch来派发一些action,这些action就会到达Reducer里面,它就会自动执行该函数,并返回一个新的state对象,再根据新的state来更新数据。数据更新后就会自动告诉订阅者,我现在数据发生改变了,需要拿新数据,界面再重新渲染

step1:创建一个项目并安装redux

step2:创建store

step3:在组件中使用

import React, {PureComponent } from 'react'
import Home from './pages/Home'
import Profile from './pages/profile'
import "./style.css"
import store from './store'export class App extends PureComponent {constructor() {super()this.state = {count: store.getState().count}}componentDidMount() {// 订阅storestore.subscribe(() => {const state = store.getState()this.setState({count: state.count})})}render() {const {count} = this.statereturn (<div><h2>App Count: {count}</h2><div className="pages"><Home /><Profile /></div></div>)}
}export default App

React-Redux

redux官方帮助我们提供了 react-redux 库,可简化在react中使用redux的过程

npm i react-reduxyarn add react-redux

Provider

在src/index.js中导入Provider,并包裹根组件→将Redux的store传递给整个应用程序→使得所有组件可访问Redux的状态

import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import { Provider } from 'react-redux';
import store from './store';const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<React.StrictMode><Provider store={store}><App /></Provider></React.StrictMode>
);

connect

connect是React-redux提供的一个高阶组件(HOC),用于将React组件与Redux的仓库联系起来;

它不会修改原始组件,而是返回一个新的、连接了Redux的组件

作用:

将Redux的状态(state) 和(dispatch)映射到组件的props

通过 mapStateToPropsmapDispatchToProps,可以自定义组件需要的状态和操作

import axios from "axios"
import * as actionTypes from  "./constants"export const calcNumber = (num) => {return {type:actionTypes.CALC_NUMBER,num}
}
import React, { PureComponent } from 'react'
import { connect } from 'react-redux'
import { calcNumber } from '../store/actionCreators'export class About extends PureComponent {calcNumber(num) {this.props.calcNumber(num)}render() {const {count,banners, recommends} = this.propsreturn (<div><h2>About:{count}</h2><button onClick={e => this.props.calcNumber(6)}>+6</button><button onClick={e => this.props.calcNumber(-6)}>-6</button><button onClick={e => this.props.calcNumber(10)}>+10</button><button onClick={e => this.props.calcNumber(-5)}>-5</button><div className="banners"><h2>轮播图数据:</h2><ul>{banners.map(item => {return <li key={item.acm}>{item.title}</li>})}</ul></div><div className="recommend"><h2>推荐数据</h2><ul>{recommends.map(item => {return <li key={item.acm}>{item.title}</li>})}</ul></div></div>)}
}function mapStateToProps(state){return {count: state.count,banners:state.banners,recommends:state.recommends}
}const mapDispatchToProps = (dispatch) => {return {calcNumber(num) {dispatch(calcNumber(num))}}
}// connect()返回值是一个高阶组件
export default connect(mapStateToProps,mapDispatchToProps)(About)

组件中进行异步操作

网络请求可以在class组件的componentDidMount中发送

store/home.js 

import axios from "axios"
import * as actionTypes from  "./constants"export const changeBanners = (banners) => {return {type:actionTypes.CHANGE_BANNERS,banners}
}export const changeRecommends = (recommends) => {return {type:actionTypes.CHANGE_RECOMMENDS,recommends}
}

Home.jsx 

import React, { PureComponent } from 'react'
import { connect } from 'react-redux'
import axios from 'axios'
import { changeBanners, changeRecommends } from '../store/actionCreators'export class Category extends PureComponent {componentDidMount() {axios.get("http://123.207.32.32:8000/home/multidata").then(res => {const banners = res.data.data.banner.listconst recommends = res.data.data.recommend.listthis.props.changeBanners(banners)this.props.changeRecommends(recommends)})}render() {return (<div><h2>Category Page:</h2></div>)}
}const mapDispatchToProps = (dispatch) => {return {changeBanners(banners) {dispatch(changeBanners(banners))},changeRecommends(recommends) {dispatch(changeRecommends(recommends))}}
}export default connect(null,mapDispatchToProps)(Category)

redux中进行异步操作

网络请求的数据也属于状态管理的一部分,我们最好还是将它放在redux中来管理

在默认情况下,dispatch(action)中传入的是一个对象→可通过reduc-thunk让dispatch中传入一个action函数

step1:安装redux-thunk

npm i redux-thunk

step2:在创建store时传入应用了middleware的enhance函数

  • 通过applyMiddleware来结合多个Middleware, 返回一个enhancer;
  • 将enhancer作为第二个参数传入到createStore中;
import { createStore,applyMiddleware } from "redux";
import {thunk} from "redux-thunk"
import reducer from "./reducer";// 正常情况下,store.dispatch(object) 只能派发一个对象
// 想要派发函数store.dispatch(function) 需要做一个增强
const store = createStore(reducer,applyMiddleware(thunk))export default store

step3:定义返回一个函数的action

import axios from "axios"
import * as actionTypes from  "./constants"export const changeBanners = (banners) => {return {type:actionTypes.CHANGE_BANNERS,banners}
}export const changeRecommends = (recommends) => {return {type:actionTypes.CHANGE_RECOMMENDS,recommends}
}export const fetchHomeMultidataAction = () => {// 如果是一个普通的action,那么我们需要返回一个对象// 问题:对象中不能直接拿到从服务器请求的数据// return {}return function(dispatch,getState) {// 异步操作:网络请求axios.get("http://123.207.32.32:8000/home/multidata").then(res => {const banners = res.data.data.banner.listconst recommends = res.data.data.recommend.list// dispatch({type:actionTypes.CHANGE_BANNERS,banners})// dispatch({type:actionTypes.CHANGE_RECOMMENDS,recommends})dispatch(changeBanners(banners))dispatch(changeRecommends(recommends))})}
}

step4:在组件中进行派发

import React, { PureComponent } from 'react'
import { connect } from 'react-redux'
import { fetchHomeMultidataAction } from '../store/actionCreators'export class Category extends PureComponent {componentDidMount() {this.props.fetchHomeMultidata()}render() {return (<div><h2>Category Page:</h2></div>)}
}const mapDispatchToProps = (dispatch) => {return {fetchHomeMultidata() {dispatch(fetchHomeMultidataAction())}}
}export default connect(null,mapDispatchToProps)(Category)

Redux模块拆分

在开发中,如果将所有的数据都存储在一个state中,随着数据越来越多,会难以管理与维护;

我们可以对其进行模块的拆分

combineReducers底层原理

redux给我们提供了一个combineReducers函数可以方便的让我们对多个reducer进行合并

实现原理:

  • 将我们传入的reducers合并到一个对象中,最终返回一个combination函数
  • 在执行combination函数的过程中,会通过判断前后返回的数据是否相同来决定返回之前的state还是新的state
  • 新的state会触发订阅者发生对应的刷新,而旧的state可以有效的组织订阅者发生刷新
// 实现原理
function reducer(state={},action) {// 返回一个对象,作为store的状态return {count:counterReducer(state.count,action),home:homeReducer(state.home,action),user:userReducer(state.user,action)}
}

Redux Toolkit(RTK)

简介

它封装了Redux的核心API,并提供了一些额外工具和约定,帮助我们更高效编写Redux代码

安装:

npm install @reduxjs/toolkit react-redux

核心API:

  • configureStore:它自动配置了 Redux 的 createStoreapplyMiddleware,并预装了一些常用的中间件(如 redux-thunkredux-devtools-extension
  • createSlice:接受reducer函数的对象、切片名称和初始状态值,并自动生成切片reducer,并带有相应的actions
  • createAsyncThunk:接受一个动作类型字符串和一个返回承诺的函数,并生成一个pending/fulfilled/rejected基于该承诺分派动作类型的 thunk

基本使用

1.configureStore创建大仓库store

import { configureStore } from "@reduxjs/toolkit";
import counterReducer from "./modules/counter";const store = configureStore({reducer: {count: counterReducer,},
});export default store;

2.createSlice创建小仓库

import { createSlice } from "@reduxjs/toolkit";const counterSlice = createSlice({name: "counter",initialState: {count: 100},reducers: {increment: (state, action) => {state.count += action.payload;},decrement: (state, action) => {state.count -= action.payload;}}   
})export const{increment, decrement} = counterSlice.actions
export default counterSlice.reducer;

3.将模块的reducer导入大仓库中

4.在组件中使用数据——还是和之前一样(Provider、connect)

异步使用

1.使用 createAsyncThunk 创建异步操作

2. 在 createSlice 中处理异步操作的结果

import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";
import axios from "axios";export const fetchHomeMultidataAction = createAsyncThunk("home/multidata", async () => {const res = await axios.get("http://123.207.32.32:8000/home/multidata");// 返回结构,那么action状态就会变成fulfilled状态return res.data;
});const homeSlice = createSlice({name: "home",initialState: {banners: [],recommends: []},reducers: {changeBanners(state, { payload }) {state.banners = payload;},changeRecommends(state, { payload }) {state.recommends = payload;}},extraReducers: (builder) => {builder.addCase(fetchHomeMultidataAction.pending, (state, action) => {console.log("fetchHomeMultidataAction pending");}).addCase(fetchHomeMultidataAction.fulfilled, (state, action) => {console.log("fetchHomeMultidataAction fulfilled");// 这里的数据不需要浅拷贝——因为内部的ImmutableJS重构了redux,并返回了一个新对象state.banners = action.payload.data.banner.list;state.recommends = action.payload.data.recommend.list;}).addCase(fetchHomeMultidataAction.rejected, (state, action) => {console.log("fetchHomeMultidataAction rejected");});}
});export const { changeBanners, changeRecommends } = homeSlice.actions;
export default homeSlice.reducer;

3.在组件中调用该函数即可——与原来使用一样

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

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

相关文章

《Android低内存设备性能优化实战:深度解析Dalvik虚拟机参数调优》

1. 痛点分析&#xff1a;低内存设备的性能困局 现象描述&#xff1a;大应用运行时频繁GC导致卡顿 根本原因&#xff1a;Dalvik默认内存参数与硬件资源不匹配 解决方向&#xff1a;动态调整堆内存参数以平衡性能与资源消耗 2. 核心调优参数全景解析 关键参数矩阵&#xff1…

STC89C52单片机学习——第38节: [17-2] 红外遥控红外遥控电机

写这个文章是用来学习的,记录一下我的学习过程。希望我能一直坚持下去,我只是一个小白,只是想好好学习,我知道这会很难&#xff0c;但我还是想去做&#xff01; 本文写于&#xff1a;2025.03.30 51单片机学习——第38节: [17-2] 红外遥控&红外遥控电机 前言开发板说明引用…

计算机组成原理————计算机运算方法精讲<1>原码表示法

第一部分:无符号数和有符号数的概念 1.无符号数 计算机中的数均存放在寄存器当中,通常称寄存器的位数为机器字长,所谓无符号数,就是指没有fu5号的数,在寄存器中的每一位均可用来存放数值,当存放有符号数时,需要留出位置存放符号,机器字长相同时,无符号数与有符号数所…

【什么是机器学习——多项式逼近】

什么是机器学习——多项式逼近 机器学习可以分成三大类别,监督学习、非监督学习、强化学习。三大类别背后的数学原理不同。监督学习使用了数学分析中的函数逼近方法和概率统计中的极大似然方法;非监督学习使用聚类和EM算法;强化学习使用马尔可夫决策过程的想法。 机器学习的…

Ubuntu 22.04 上安装阿里云 CLI(命令行工具)

在 Ubuntu 22.04 上安装阿里云 CLI&#xff08;命令行工具&#xff09;可以通过以下步骤完成&#xff1a; 步骤 1&#xff1a;下载阿里云 CLI 安装包 打开终端&#xff0c;首先更新你的软件包索引&#xff1a; sudo apt update安装 curl&#xff08;如果还没有安装&#xff09…

​Android Gradle 插件(AGP)版本与 ​Gradle 版本需要严格对应

一、AGP 与 Gradle 版本对照表 Android Gradle 插件版本对应 Gradle 版本适用 Android Studio 版本​8.1.x8.2Arctic Fox (2020.3.1+)​8.0.x8.0Arctic Fox (2020.3.1+)​7.4.x7.5.1IntelliJ IDEA 2022+​7.3.x7.4IntelliJ IDEA 2022+​7.2.x7.3.3IntelliJ IDEA 2021.3+​7.1.x…

【Matlab】-- 基于MATLAB的灰狼算法优化支持向量机的回归算法

文章目录 文章目录 01 内容概要02 GWO-SVR模型03 部分代码04 运行结果05 参考文献06 代码下载 01 内容概要 GWOSVR&#xff08;基于灰狼算法优化的支持向量机回归&#xff09;是一种先进的机器学习技术&#xff0c;它结合了灰狼优化算法&#xff08;Grey Wolf Optimizer, GWO…

Google Play Games PC版即将正式上线!

早在 2021 年&#xff0c;谷歌就推出 Google Play Games PC 版&#xff0c;本质上是基于虚拟化创建安卓系统在 Windows 上运行 Google Play 平台的各种游戏。 在测试了 4 年后&#xff0c;谷歌准备在今年晚些时候正式上线该平台&#xff0c;谷歌将在下周举办 2025 游戏开发者大…

【SpringBoot】深入解析使用配置文件解决硬编码问题综合练习(三):解析验证码拓展问题

校验输入验证码接口 check( ) 5. 为什么要用静态内部类接收配置文件中的 Seisson 对象&#xff1f; 为什么我们接收配置文件的 Session 对象时&#xff0c;使用静态内部类给 Session 对象的 key&#xff0c;date 属性赋值呢&#xff1f;不加 static 可以吗&#xff1f; 在 Cap…

day16 学习笔记

文章目录 前言一、广播机制二、数组遍历1.for循环2.nditer函数 三、数组操作1.reshape函数2.flat属性3.flatten函数4.revel函数5.数组转置6.升维与降维7.数组的连接与分割8.数组运算 前言 通过今天的学习&#xff0c;我进一步掌握了更多numpy的语法知识 一、广播机制 广播&am…

使用FastExcel时的单个和批量插入的问题

在我们用excel表进行插入导出的时候&#xff0c;通常使用easyexcel或者FastExcel&#xff0c;而fastexcel是easy的升级版本&#xff0c;今天我们就对使用FastExcel时往数据库插入数据的业务场景做出一个详细的剖析 场景1 现在我们数据库有一张组织表&#xff0c;组织表的字段…

Cannot find a valid baseurl for repo: centos-sclo-sclo/x86_64

​ rpm -Uvh https://repo.zabbix.com/zabbix/5.0/rhel/7/x86_64/zabbix-release-latest-5.0.el7.noarch.rpmyum clean allyum macache fast​ 编辑配置文件 /etc/yum.repos.d/zabbix.repo and enable zabbix-frontend repository. [zabbix-frontend]...enabled1... 下载相关…

AI基础02-图片数据采集

上篇文章我们学习了文本的数据采集&#xff0c;今天主要了解一下图片数据采集的方法。图片采集方法通常有网页采集和实时采集&#xff08;传感器采集&#xff09;两种。我们学习一下如何利用python 工具和笔记本计算机摄像头进行图片数据的实时采集。 1&#xff09;cv2库简介 …

【CSS】相对位置小练习

要求&#xff1a; 成果&#xff1a; 代码&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>相对位置小练习</title><link rel"stylesheet" href"./css/style.css…

外设的中断控制

如ADC、SPI、I2C、TIM等使用STM32 HAL库时的中断函数调用方式和UART非常类似&#xff0c;都有底层直接使能中断和上层库函数管理两种方式。下面详细说明几种典型外设&#xff1a; 一、ADC外设 &#xff08;1&#xff09;直接使能中断&#xff08;底层控制&#xff09;&#xf…

网络传输优化之多路复用与解复用

一、基本概念 多路复用 发送端将来自多个应用或进程的数据流合并到同一物理信道中传输的过程。核心目的是提高信道利用率&#xff0c;减少资源浪费。例如&#xff0c;多个网络应用&#xff08;如浏览器、邮件客户端&#xff09;通过不同端口将数据封装为报文段&#xff0c;共享…

【软考-架构】10.1、软件工程概述-CMM-软件过程模型-逆向工程

✨资料&文章更新✨ GitHub地址&#xff1a;https://github.com/tyronczt/system_architect 文章目录 软件工程基础知识软件工程概述能力成熟度模型能力成熟度模型CMM能力成熟度模型集成CMMI &#x1f4af;考试真题第一题第二题 软件过程模型瀑布模型&#xff08;SDLC&#…

python将整个txt文件写入excel的一个单元格?

要将整个txt文件写入Excel的一个单元格&#xff0c;可以使用Python的openpyxl库来实现。以下是一个简单的示例代码&#xff1a; from openpyxl import Workbook# 读取txt文件内容 with open(file.txt, r) as file:txt_content file.read()# 创建一个新的Excel工作簿 wb Work…

车载以太网网络测试 -25【SOME/IP-报文格式-1】

1 摘要 本专题接着上一专题对SOME/IP进行介绍&#xff0c;主要对SOME/IP报文格式以及定义的字段进行详细介绍&#xff0c;有助于在实际项目过程中对SOME/IP报文的理解。 上文回顾&#xff1a; 车载以太网网络测试 -24【SOME/IP概述】 2 SOME/IP-报文格式 通过上个专题介绍&a…

【区块链安全 | 第五篇】DeFi概念详解

文章目录 DeFi1. DeFi 生态概览2. 去中心化交易所&#xff08;DEX&#xff09;2.1 AMM&#xff08;自动做市商&#xff09;模型2.2 订单簿模式&#xff08;现货交易&#xff09; 3. 借贷协议3.1 Aave3.2 使用闪电贷&#xff08;Flash Loan&#xff09; 4. 稳定币&#xff08;St…