React@16.x(60)Redux@4.x(9)- 实现 applyMiddleware
目录
- 1,applyMiddleware 原理
- 2,实现
- 2.1,applyMiddleware
- 2.1.1,compose 方法
- 2.1.2,applyMiddleware
- 2.2,修改 createStore
接上篇文章:Redux中间件介绍。
1,applyMiddleware 原理
Redux 应用中间件方式:
const store = createStore(reducer, applyMiddleware(logger1, logger2));
实际会转为下面的方式执行:
const store = applyMiddleware(logger1, logger2)(createStore)(reducer)
applyMiddleware会确定用到的中间件;它会返回一个用来创建仓库的函数A,参数是createStore;- 函数 A,会返回创建仓库的函数B,和
createStore函数差不多。 - 函数B,会对中间件函数做处理,并修改原始
dispatch。
大致相当于:
export const applyMiddleware = (...middlewares) => {// 用来创建的仓库的函数return (createStore) => {// 创建仓库的函数return (reducer, defaultState) => {const store = createStore(reducer, defaultState)const dispatch = '经过 middlewares 处理的 store.dispatch'return {...store,dispatch}}}
}
2,实现
2.1,applyMiddleware
上篇文章介绍了 中间件函数 的写法和多个中间件函数的执行顺序。
基于此,实现这个 dispatch 流转的逻辑,并得到最终的 dispatch 即可完成 applyMiddleware。
2.1.1,compose 方法
关键要实现
const resultDispatch = logger1(logger2(logger3(store.dispatch)))
实现:
/*** @param {...any} funcs* @returns {function}*/
export const compose = (...funcs) => {if (funcs.length === 0) {return (args) => args;} else if (funcs.length === 1) {return funcs[0];}return (...args) => {let lastReturn = null;for (let i = funcs.length - 1; i >= 0; i--) {const func = funcs[i];if (i === funcs.length - 1) {lastReturn = func(...args);} else {lastReturn = func(lastReturn);}}return lastReturn;};
};
// 测试代码
const add = (n) => {return n + n;
};const mult = (n) => {return n * n;
};const b = compose(add, mult);
console.log(b(3)); // 先乘后加,18
可使用 Array.reduce 简化:
export const compose = (...funcs) =>funcs.reduce((prev, next) =>(...args) =>prev(next(...args)));
2.1.2,applyMiddleware
import { compose } from "./compose";
export const applyMiddleware = (...middlewares) => {return (createStore) => {return (reducer, defaultState) => {const store = createStore(reducer, defaultState);let dispatch = () => {throw new Error("目前还不能使用 dispatch");};// 传递给中间件函数的 store 只有这2个属性。const simpleStore = {getState: store.getState,dispatch: (...args) => dispatch(...args), // 每个中间件函数的 dispatch 都是上一个中间件组装后的};// 获取用于创建 dispatch 的函数const dispatchProducts = middlewares.map((m) => m(simpleStore));// 重新组装后的 dispatchdispatch = compose(...dispatchProducts)(store.dispatch);return {...store,dispatch,};};};
};
2.2,修改 createStore
之前实现的 createStore,没有对可能的第3个函数做处理。这里补充下:
- 如果第2个参数是
applyMiddleware,那说明没有defaultState。
这里就简单判断写第2个参数是不是函数,实际源码中
defaultState也可以通过一个函数创建。
export const createStore = (reducer, defaultState, enhancer) => {// enhancer 表示 applymiddleware 返回的函数。if (typeof defaultState === 'function') {enhancer = defaultStatedefaultState = undefined}if (typeof enhancer === 'function') {enhancer(createStore)(reducer, defaultState)}// 其他剩余代码没有做变动。// ...
}
完整代码
export const createStore = (reducer, defaultState, enhancer) => {// enhancer 表示 applymiddleware 返回的函数。if (typeof defaultState === "function") {enhancer = defaultState;defaultState = undefined;}if (typeof enhancer === "function") {enhancer(createStore)(reducer, defaultState);}let currentReducer = reducer;let currentState = defaultState;let listeners = [];const dispatch = (action) => {if (typeof action !== "object" || Object.getPrototypeOf(action) !== Object.prototype) {throw new Error("action 必须是一个 plain Object");}if (action.type === undefined) {throw new Error("action 必须有 type 属性");}currentState = currentReducer(currentState, action);// 每次更新时,遍历监听器。for (const listener of listeners) {listener();}};const getState = () => {return currentState;};const subscribe = (listener) => {listeners.push(listener);let isRemove = false;// 取消监听return () => {if (isRemove) {return;} else {isRemove = true;listeners = listeners.filter((f) => f !== listener);}};};// createStore 创建时会调用一次。dispatch({type: `@@redux/INIT${getRandomString}`,});return {dispatch,getState,subscribe,};
};function getRandomString() {return Math.random().toString(36).substring(2, 8).split("").join(".");
}
以上。
相关文章:
React@16.x(60)Redux@4.x(9)- 实现 applyMiddleware
目录 1,applyMiddleware 原理2,实现2.1,applyMiddleware2.1.1,compose 方法2.1.2,applyMiddleware 2.2,修改 createStore 接上篇文章:Redux中间件介绍。 1,applyMiddleware 原理 R…...
level 6 day1 Linux网络编程之网络基础
v1 网络的历史和分层 TCP 是可靠传输,IP协议是不可靠传输 网络的体系结构 网络分层的思想: OSI体系结构 两层交换机是指数据链路层的交换 三层交换是指网络层这边的交换 四层模型 蓝色的字 是由手机发给PC机,由传输层来决定应该交给哪一…...
PostgreSQL UPDATE 命令
PostgreSQL UPDATE 命令 PostgreSQL 是一种功能强大的开源对象关系型数据库管理系统(ORDBMS),它使用并扩展了SQL语言。在处理数据库时,我们经常需要更新现有的记录。在PostgreSQL中,UPDATE命令用于修改表中的现有记录…...
什么? CSS 将支持 if() 函数了?
CSS Working Group 简称 CSSWG, 在近期的会议中决定将 if() 添加到 CSS Values Module Level 5 中。 详情可见:css-meeting-bot 、[css-values] if() function 当我看到这个消息的时候,心中直呼这很逆天了,我们知道像 less 这些 css 这些预…...
function calling实现调用理杏仁api获取数据
LLM是不存在真正逻辑的且并不是知晓万事万物的(至少目前是这样)在很多更垂直的环境下LLM并不能很好的赋能。 function calling的实现使LLM可以对接真正的世界以及真正有逻辑的系统,这将很大程度上改变LLM的可用范围(当然安全问题依…...
Excel中用VBA实现Outlook发送当前工作簿
Excel中用VBA实现Outlook发送当前工作簿,首先按AltF11打开VBA编辑器,插入模块,并在工具-引用中勾选 Microseft Outlook .0 Object Library(其中为你Microseft Outlook的版本号。 Sub 发送邮件() 保存当前excel ThisWorkbook.Save让excel连接…...
从 ArcMap 迁移到 ArcGIS Pro
许多 ArcMap 用户正在因 ArcGIS Pro 所具有的现代 GIS 桌面工作流优势而向其迁移。 ArcGIS Pro 与其余 ArcGIS 平台紧密集成,使您可以更有效地共享和使用内容。 它还将 2D 和 3D 组合到一个应用程序中,使您可以在同一工程中使用多个地图和多个布局。 Arc…...
WSL2 的安装与运行 Linux 系统
前言 适用于 Linux 的 Windows 子系统 (WSL) 是 Windows 的一项功能,允许开发人员在 Windows 系统上直接安装并使用 Linux 发行版。不用进行任何修改,也无需承担传统虚拟机或双启动设置的开销。 可以将 WSL 看作也是一个虚拟机,但是它更为便…...
业务终端动态分配IP-DHCP技术、DHCP中继技术
一、为什么需要DHCP? 1、许多设备(主机、无线WiFi终端等)需要动态地址的分配; 2、人工手工配置任务繁琐、容易出错,比如:IP地址冲突; 3、网络规模扩大、复杂度提高,网络配置越来越复杂,计算机的位置变化和数量超过可分配IP地址的数量,造成IP地址变法频繁以及IP地址…...
新一代大语言模型 GPT-5 对工作与生活的影响及应对策略
文章目录 📒一、引言 📒二、GPT-5 的发展背景 🚀(一)GPT-4 的表现与特点 🚀(二)GPT-5 的预期进步 📒三、GPT-5 对工作的影响 🚀(一…...
AI基于大模型语言存在的网络安全风险
目的: 随着大语言模型(LLM)各领域的广泛应用,我们迫切需要了解其中潜在的风险和威胁,及时进行有效的防御。 申明: AI技术的普及正当的使用大模型技术带来的便利,切勿使用与非法用途ÿ…...
探索Perl语言:入门学习与实战指南
文章目录 探索Perl语言:入门学习与实战指南一、Perl语言概述二、Perl的安装与配置安装PerlWindowsmacOSLinux 配置Perl 三、基本语法与数据类型标量变量数组哈希 四、控制结构条件语句循环语句 五、子程序与模块子程序模块 六、文件操作与正则表达式文件读取与写入正…...
dp or 数学问题
看一下数据量,只有一千,说明这个不是数学问题 #include<bits/stdc.h> using namespace std;#define int long long const int mo 100000007; int n, s, a, b; const int N 1005;// 2 -3 // 1 3 5 2 -1 // 1 -2 -5 -3 -1 int dp[N][N]; int fun…...
kibana连接elasticsearch(版本8.11.3)
前言 elasticsearch在8版本之后就出现了很大变化,由于kibana版本需要需elasticsearch进行版本对象,kibana连接方式也出现了很大变化。我在这里记录下自己的踩坑记录。 服务部署 本文中的服务都是在docker环境中部署的。其中elasticsearch版本和kibana版…...
基于python的图像去水印
1 代码 import cv2 import numpy as npdef remove_watermark(image_path, output_path):# 读取图片image cv2.imread(image_path)# 转换为灰度图gray cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)# 使用中值滤波去除噪声median_filtered cv2.medianBlur(gray, 5)# 计算图像的梯…...
Linux下Supervisor的安装与配置
软件工程中,守护进程是非常行之有效的方案。能够让我们的一些指令在崩溃之后可以自我重新启动,从而保障业务上的持续使用。 这里就从0开始教大家安装Supervisor。 一,下载安装 安装有好多种方法,直接下载安装包安装,或者yum安装或者pip安装都可以。这次我们选择的是pip…...
使用Pandas读取Excel文件将特定列转成str格式方法汇总
文章目录 读取Excel文件并确保列为字符串类型使用 dtype 参数使用 converters 参数 读取Excel文件的正确拼写示例:读取Excel文件并过滤包含特定值的行详细解释 读取Excel文件并确保列为字符串类型 正确的方法是使用 pd.read_excel 函数,并指定 dtype 或…...
FPGA CFGBVS 管脚接法
说明 新设计了1个KU040 FPGA板子,回来之后接上JTAG FPGA不识别。做如下检查: 1、电源测试点均正常; 2、查看贴片是否有漏焊,检查无异常,设计上NC的才NC; 3、反复检查JTAG接线是否异常,贴片是…...
快速排序及归并排序的实现与排序的稳定性
目录 快速排序 一. 快速排序递归的实现方法 1. 左右指针法 步骤思路 为什么要让end先走? 2. 挖坑法 步骤思路 3. 前后指针法 步骤思路 二. 快速排序的时间和空间复杂度 1. 时间复杂度 2. 空间复杂度 三. 快速排序的优化方法 1. 三数取中优化 2. 小区…...
【系统架构设计】数据库系统(一)
数据库系统(一) 数据库模式与范式数据库的结构与模式数据模型关系代数数据的规范化反规范化 数据库设计事务管理备份与恢复分布式数据库系统数据仓库数据挖掘NoSQL大数据 数据库模式与范式 数据库的结构与模式 数据库技术中采用分级的方法将数据库的结…...
集团化全员学习企业在线学习平台选型指南|政企专属解决方案
在数字化人才培养浪潮下,集团化全员学习已成为央企、国企、大型上市公司的核心战略,而一款稳定、可管控、高合规的企业在线学习平台,是支撑万人级培训的核心底座。传统分散式培训存在管理混乱、标准不统一、效果不可追溯等痛点,本…...
好书推荐《VirtualLab Fusion入门与进阶实用教程(第二版)》
目 录第一章 VirtualLab Fusion理论基础 1 1.1 几何光学和光线追迹 1 1.2 物理光学和光场追迹 1 1.2.1 统一场追迹 3 1.2.2 第二代场追迹 6 第二章 VirtualLab Fusion安装与更新 10 2.1 VirtualLab 版本说明及系统配置要求 10 2.2 VirtualLab安装与更新 11 2.3 安装过程中可能遇…...
别再只会用现成镜像了!手把手教你用Diskimage-builder从零打造专属OpenStack镜像(Ubuntu 22.04实战)
从零构建OpenStack定制镜像:Diskimage-builder深度实践指南 为什么需要定制镜像? 在OpenStack云环境中,标准镜像就像未经调味的食材——虽然能用,但远不能满足专业需求。想象一下,每次创建实例后都要重复安装Python环境…...
【会议征稿通知 | E3S出版 | EI 、Scopus稳定检索】第十二届能源材料与环境工程国际学术会议(ICEMEE 2026)
第十二届能源材料与环境工程国际学术会议(ICEMEE 2026) 2026 12th International Conference on Energy Materials and Environment Engineering 2026年6月12-14日 | 线上会议 大会官网:www.icemee.net 截稿时间:见官网&#x…...
书评质量断崖式提升的关键一步,Perplexity辅助写作的3层认知跃迁与2个致命误用陷阱
更多请点击: https://kaifayun.com 第一章:书评质量断崖式提升的关键一步,Perplexity辅助写作的3层认知跃迁与2个致命误用陷阱 Perplexity 不是搜索引擎的替代品,而是面向深度思考的“认知协作者”。当用于技术书评写作时&#x…...
Unity3D RPG游戏开发实战:从零搭建角色与场景交互系统(含源码)
1. Unity3D RPG游戏开发基础准备 第一次打开Unity3D时,很多人会被复杂的界面吓到。别担心,我们先从最基础的设置开始。我建议使用2021 LTS版本,这个版本稳定性好,社区支持也完善。安装完成后,记得在Hub里勾选"Wi…...
MIUI手机管家自动任务还能这么玩?手把手教你用备用机+智能插座实现远程打卡(附详细避坑指南)
MIUI自动任务高阶玩法:备用机智能插座打造远程打卡系统全攻略 1. 为什么需要远程打卡解决方案? 早晨8:55分的地铁车厢里,小李盯着手机上的导航地图,红色拥堵路段让他的心跳加速——距离公司打卡截止时间只剩5分钟,而至…...
MPh 开源项目教程
MPh 开源项目教程 【免费下载链接】MPh Pythonic scripting interface for Comsol Multiphysics 项目地址: https://gitcode.com/gh_mirrors/mp/MPh 项目介绍 MPh 是一个基于 Python 的强大开源项目,旨在简化数学物理问题的求解过程。它结合了符号计算的灵活…...
AD画完板子别急着下单!5分钟搞定DRC规则检查,避开这些坑才能顺利发嘉立创
AD设计必看:DRC规则检查深度解析与实战避坑指南 在PCB设计领域,完成布线只是成功的一半。许多工程师在AD(Altium Designer)中精心设计完电路板后,常常因为忽略DRC(Design Rule Check)检查而遭遇生产返工、延迟甚至完全报废的惨痛经历。本文将…...
HC32F4A0外设引脚自由配置全攻略:如何像STM32重映射一样灵活规划你的原理图?
HC32F4A0外设引脚自由配置全攻略:如何像STM32重映射一样灵活规划你的原理图? 在嵌入式硬件设计中,引脚规划往往是决定项目成败的关键第一步。传统MCU如STM32通过固定功能引脚和有限的重映射功能,给工程师带来诸多限制。而华大半导…...
