Redux中间件源码解析与实现

基本介绍

本文中涉及到的关键npm包的版本信息如下:
react 的版本为18.2.0
redux的版本为4.1.2
redux-thunk版本为2.4.2
redux-promise版本为0.6.0
redux-logger版本为3.0.6

在Redux源码解析与实现(一)Redux源码解析与实现(二)这两篇文章中,详细讲解了怎么实现一个Redux的核心功能,而Redux默认只能够处理plainObject的参数,所以我们需要引用各种中间件来加强dispatch,使其能够传递异步函数或者是promise或者是其他的能力,比如说打日志。每个中间件往往也只做一件特定的事情,比如redux-thunk就是可以处理函数redux-logger可以打印出日志redux-promise可以处理actionpromise的情况。而且下一个中间件的接受的action为上一个中间件的处理的结果,如下图所示:

请添加图片描述

基本使用

我们建一个简单的demo,看看redux-promise、redux-promise、redux-logger是如何使用的。我们只需要在createStore方法中传递经过applyMiddleware处理过的中间件即可,核心代码如下:

// store/index.js
import thunk from 'redux-thunk'
import logger from 'redux-logger'
import promise from 'redux-promise'const store = createStore(rootReducer,// logger 要在thunk的后面,dispatch接受的参数可能是函数经过thunk处理之后再return一个planObject再交给logger处理applyMiddleware(promise, thunk, logger)
)

// ReduxPage.jsx
import React from "react";
import store from "../store";
import './index.css'export default class ReduxPage extends React.Component {componentDidMount() {// 新增订阅,在这里订阅的逻辑就是当状态管理库store中数据更新时,组件也需要更新一下this.unsubscribe = store.subscribe(() => {this.forceUpdate()})}componentWillUnmount() {// 组件卸载 -> 自然需要取消订阅this.unsubscribe()}add = () => {store.dispatch({type: "ADD"})}asyncAdd = () => {store.dispatch((dispatch, getState) => {console.log('getState pre:', getState());// 使用setTineout模拟后端请求setTimeout(() => {// 拿到服务端数据,处理完数据之后再dispatchdispatch({type: "ADD", payload: 10})console.log('getState after:', getState());}, 1000)})}promiseAdd = () => {// dispatch接受一个promise的参数// store.dispatch(Promise.resolve({type: 'ADD', payload: 20}))store.dispatch(new Promise((resolve, reject) => {setTimeout(() => {resolve({type: 'ADD', payload: 20})}, 1000)}))}minus = () => {store.dispatch({type: "MINUS"})}setName = () => {store.dispatch({type: "SET_NAME", payload: `hyy${Math.random()}`})}setAge = () => {store.dispatch({type: "SET_AGE", payload: Math.random() * 100})}render() {return (<div><div> ReduxPage </div><div><span className="box">count: {store.getState().count}</span><span className="box">name: {store.getState().userInfo.name}</span><span className="box">age: {store.getState().userInfo.age}</span></div><div className="wrap"><button onClick={this.add}>add</button><button onClick={this.asyncAdd}>asyncAdd</button><button onClick={this.promiseAdd}>promiseAdd</button><button onClick={this.minus}>minus</button></div><div className="wrap"><button onClick={this.setName}>setName</button><button onClick={this.setAge}>setAge</button></div></div>);}
}

经过Redux源码解析与实现(一)Redux源码解析与实现(二)我们知道在用户在dispatch的时候会依次执行各个中间件,而中间件会接受到dispatch & getStore这个对象以读写store中的数据然后返回值给下一个中间件执行。直至最后应该得到一个plainObject传递给原始的dispatch执行。其中通过applyMiddleware接受到的若干个中间件函数数组则是使用了函数式编程思想中函数聚合的方式依次执行。

redux中间件的基本使用demo

源码分析

经过上面的分析,所有的中间件的代码架子均如下所示:

function xxx({getState, dispatch}) {// next就是聚合函数componse中的下一个要执行的函数(reducer中的func)return (next) => (action) => {// todo...// returnValue就是该中间件处理完之后返回给下一个中间件的值return returnValue;};
}

代码实现

redux-promise

这个中间件主要是判断当前传递的参数即action是否是promise,如果是的话,那我们就需要通过promise的方式获取值然后返回给下一个中间件,如果不是的话,那就直接运行当前函数即可。其代码基本实现如下:

function promise({getState, dispatch}) {return (next) => (action) => {// 判断传递进来的action是否为promisereturn isPromise(action) ? action.then(dispatch) : next(action);};
}

redux-thunk

这个中间件主要是判断当前的action是否是函数,如果是函数的话,那就执行该函数并将dispatch & getStore两个操作状态管理库的API传递给这个函数,这个函数执行的结果return给下一个中间件的入参,如果不是一个函数,那就将action传递给当前函数执行&返回结果给下一个中间件其主要核心代码如下:

// 自定义thunk中间件
// 中间件接受的参数就是middlewareAPI即getState & dispatch 让中间件有操作状态管理库的权限
function thunk({getState, dispatch}) {// ! next就是聚合函数componse中的下一个要执行的函数(reducer中的func)而不是下一个中间件return (next) => (action) => {if (typeof action === "function") {// 如果接受到一个函数的话就执行这个函数 & 把dispatch和getState作为参数传递给这个函数// 所以业务代码传递给dispatch的函数参数可以接受dispatch, getState这两个参数return action(dispatch, getState);}// 如果action不是函数那就正常执行 并把当前函数执行的值return给下一个中间件return next(action);};
}

redux-logger

这个中间件主要是在dispatch的时候打印出了一些日志,便于我们做数据追踪,我们可以在数据修改之前(即dispatch之前打印出原始数据 )+ action动作和数据被修改之后(即dispatch之后的store中的数据)
其核心代码如下:

// 自定义logger 中间件
function logger({getState, dispatch}) {return (next) => (action) => {console.log("------------------------------------------");console.log("prev state", getState());console.log(`${action.type ? `ACTION: ${action.type + "已被执行~"}` : '接受到action为非plainObject'}`);const returnValue = next(action);console.log("next state", getState());console.log("------------------------------------------");return returnValue;};
}

我们将示例中的中间件部分换成我们自己开发的中间件查看下效果:
请添加图片描述

线上demo: redux中间件的基本实现

相关资料

redux
redux-thunk
redux-logger
redux-promise
Redux源码解析与实现(一)
Redux源码解析与实现(二)
redux中间件的基本使用demo
redux中间件的基本实现

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

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

相关文章

【三维重建】【深度学习】【数据集】基于COLMAP制作个人Gen6D测试数据集

【三维重建】【深度学习】【数据集】基于COLMAP制作个人Gen6D测试数据集 提示:最近开始在【三维重建】方面进行研究,记录相关知识点,分享学习中遇到的问题已经解决的方法。 文章目录 【三维重建】【深度学习】【数据集】基于COLMAP制作个人Gen6D测试数据集前言下载安装colmap软…

云备份——数据信息管理模块

一&#xff0c;数据信息管理模块设计 该模块主要用于服务端对备份的文件进行数据信息管理&#xff0c;以便于业务处理模块或者热点管理模随用随取&#xff0c;以及在网页上迅速的显示备份文件列表&#xff0c;因此该模块需要管理的信息也是根据后续业务处理模块以及热点管理模块…

变电站自动化监控系统

力安科技变电站自动化监控系统是以箱式变电站为管理对象&#xff0c;加装箱变网关&#xff0c;在完成箱变智能化改造的基础上&#xff0c;依托电易云&#xff0c;构建一体化智慧箱变及运维系统。智能箱式变电站被广泛应用于住宅小区、城市公用变压器、工厂、商场、机场、电站等…

服务器数据恢复-阵列崩溃导致LVM结构破坏的数据恢复案例

服务器数据恢复环境&#xff1a; 一台服务器中有两组分别由4块SAS硬盘组建的raid5阵列&#xff0c;两组阵列上层划分LUN组建LVM结构&#xff0c;并被格式化为EXT3文件系统。 服务器故障&检测&#xff1a; RIAD5阵列中有一块硬盘故障离线&#xff0c;热备盘激活上线顶替离线…

pdf怎么合并在一起?几种方法快速合并

pdf怎么合并在一起&#xff1f;在处理PDF文件时&#xff0c;有时需要将多个PDF文件合并成一个文件。这种操作在日常学习、工作和生活中很常见。但是&#xff0c;如果没有专业的PDF工具&#xff0c;这项任务可能会变得非常繁琐、耗时和费力。因此&#xff0c;我们需要一款功能强…

运行Android Automotive模拟器

在windows系统中安装MobaXterm MobaXterm free Xserver and tabbed SSH client for Windows 运行MobaXterm&#xff0c;在宿主机中进入编译后的源码根目录并执行如下命令&#xff0c;若未编译&#xff0c;请参照如下链接&#xff0c;编译车机模拟器Android Automotive编译_IT…

Qt开发_调用OpenCV(3.4.7)设计完成人脸检测系统

一、前言 近年来,人脸识别技术得到了广泛的应用,它可以在各种场景中实现自动化的人脸检测和识别,例如安防监控、人脸解锁、人脸支付等。 该项目的目标是设计一个简单易用但功能强大的人脸检测系统,可以实时从摄像头采集视频,并对视频中的人脸进行准确的检测和框选。通过…

【Mycat1.6】缓存不生效问题处理

背景 系统做读写分离&#xff0c;有大量读需求&#xff0c;基本没有实时获取数据业务需要&#xff0c;所以可以启用缓存来减缓数据库压力&#xff0c;传统使用mybatis的缓存需要大量侵入式声明&#xff0c;所以结合需求使用Mycat中间件来满足 数据库结构 mysql-master&#…

Android Glide preload RecyclerView切入后台不可见再切换可见只加载当前视野可见区域item图片,Kotlin

Android Glide preload RecyclerView切入后台不可见再切换可见只加载当前视野可见区域item图片&#xff0c;Kotlin <uses-permission android:name"android.permission.READ_EXTERNAL_STORAGE" /><uses-permission android:name"android.permission.RE…

linux 内存一致性

linux 出现内存一致性的场景 1、编译器优化 &#xff0c;代码上下没有关联的时候&#xff0c;因为编译优化&#xff0c;会有执行执行顺序不一致的问题&#xff08;多核单核都会出现&#xff09; 2、多核cpu乱序执行&#xff0c;cpu的乱序执行导致内存不一致&#xff08;多核出…

Sui上低Gas费为预言机注入强大动力

在当今世界中&#xff0c;大数据推动了许多真正有用的应用发展&#xff0c;预言机是将这些数据引入区块链的手段。然而&#xff0c;通过预言机进行数据调用需要在区块链上进行交易&#xff0c;并支付相关gas费。Sui保持稳定且低廉gas费的能力&#xff0c;使其成为依赖预言机app…

密码找回安全

文章目录 密码找回安全任意秘密重置 密码找回安全 用户提交修改密码请求;账号认证:服务器发送唯一ID (例如信验证码)只有账户所有者才能看的地方&#xff0c;完成身份验证&#xff1b;身份验证:用户提交验证码完成身份验证;修改密码:用户修改密码。 任意秘密重置 登录metinfo4…