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(".");
}

以上。

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

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

相关文章

iOS——MRC与ARC以及自动释放池深入底层学习

MRC与ARC再回顾 在前面,我们简单学了MRC与ARC。MRC指手动内存管理,需要开发者使用retain、release等手动管理对象的引用计数,确保对象在必要时被释放。ARC指自动内存管理,由编译器自动管理对象的引用计数,开发者不需要…

基于springboot和mybatis的RealWorld后端项目实战一之hello-springboot

新建Maven项目 注意archetype选择quickstart pom.xml 修改App.java App.java同级目录新增controller包 HelloController.java package org.example.controller;import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotatio…

浅析stm32启动文件

浅析stm32启动文件 文章目录 浅析stm32启动文件1.什么是启动文件?2.启动文件的命名规则3.stm32芯片的命名规则 1.什么是启动文件? 我们来看gpt给出的答案: STM32的启动文件是一个关键的汇编语言源文件,它负责在微控制器上电或复位…

【简历】惠州某二本学院:前端简历指导,秋招面试通过率为0

注:为保证用户信息安全,姓名和学校等信息已经进行同层次变更,内容部分细节也进行了部分隐藏 简历说明 这是一份25届二本同学,投递前端职位的简历,那么在校招环节二本同学主要针对的还是小公司,这个学校因为…

LVS+Nginx高可用集群---搭建高可用集群负载均衡

1.LVS简介 Lvs(Linux Virtual Server):使用集群,对于整个用户来说是透明,用户访问的时候是单个高性能的整体。道理与nginx类似 LVS网络拓扑图:是基于四层。 用户通过浏览器发送请求,然后到达LVS.Lvs根据相应算法将…

AI PC创造新商机,ISP与HPD集成单芯片方案受欢迎

今年以来,AI PC逐渐成为市场的焦点,因为AI PC给多年一成不变的PC市场带来了新的看点,也给了消费者升级的理由。今年是AI PC的元年,上半年不论是芯片厂商,还是PC厂商都在AI PC市场快速布局。AI PC相关的大模型、生态&am…

ollama + fastgpt 搭建免费本地知识库

目录 1、ollama ollama的一些操作命令: 使用的方式: 2、fastgpt 快速部署: 修改配置: config.json: docker-compose.yml: 运行fastgpt: 访问OneApi: 添加令牌和渠道: 登陆fastgpt,创建知识库和应用 3、总结: 附录: 1. 11434是ollama的端口: 2. m3e 测…

处理多维特征的输入(Multiple Dimension Input)

输入x有多个特征features,最终得到输出y的类别。 在上一节提到,左边是我们最开始了解的线性回归,右边是我们的logistics回归(返回值为一个离散的集合)。对于本节,就是在logistics回归输入x的基础上让其多一…

中伟视界:矿山智能化——AI引领创新,行车不行人检测算法实现实时预警,防范行车不行人事故发生

行车不行人检测AI分析算法通过利用人工智能和深度学习技术,对井下行人和车辆的行驶情况进行实时检测和识别。该算法在提升矿山安全管理、减少事故发生方面具有重要作用。本文将详细介绍该AI算法的识别过程、应用场景及其技术特点。 一、识别过程 行车不行人检测AI分…

Hadoop安装报错

报错:ERROR 2023-03-09 21:33:00,178 NetUtil.py:97 - SSLError: Failed to connect. Please check openssl library versions. 解决方案: 在安装失败得客户端执行 编辑 /etc/python/cert-verification.cfg 配置文件,将 [https] 节的 verify 项 设为禁用…

怎么查看一个网站的ip地址?

1、使用nslookup nslookup 是一个网络诊断工具,用于查询域名系统(DNS)记录,将域名解析为IP地址,或者查询其他DNS记录类型,如MX(邮件交换记录)、CNAME(别名记录&#xff…

css - - - - - 环形倒计时进度条实现

css - - - - - 环形倒计时进度条实现 1. 效果图展示2. 代码展示 1. 效果图展示 2. 代码展示 // html <view class"father"><view class"progress" style"--progress:{{red}}; --last:{{gray}}"></view> </view>// css …

mac合并pdf文件最简单的方法,mac如何合并pdf文件

在数字化办公和学习的过程中&#xff0c;pdf 格式因其稳定性和跨平台兼容性而广受欢迎。但有时候&#xff0c;我们免不了需要将多个pdf文件合并为一个&#xff0c;以便于管理和分享。今天&#xff0c;就让我来为大家介绍几种简单高效的pdf合并方法&#xff0c;让你轻松合并文件…

深度学习落地实战:手势识别

前言 大家好&#xff0c;我是机长 本专栏将持续收集整理市场上深度学习的相关项目&#xff0c;旨在为准备从事深度学习工作或相关科研活动的伙伴&#xff0c;储备、提升更多的实际开发经验&#xff0c;每个项目实例都可作为实际开发项目写入简历&#xff0c;且都附带完整的代…

Android 11 HAL层集成FFMPEG

1.集成目录&#xff1a; android/vendor/noch/common/external/NoboMediaCodec 2.文件夹目录 3. Android.mk实现 # Copyright #LOCAL_PATH : $(call my-dir)SF_COMMON_MK : $(LOCAL_PATH)/common.mkinclude $(call first-makefiles-under,$(LOCAL_PATH))4.common.mk实现 # #…

【EI检索】第二届机器视觉、图像处理与影像技术国际会议(MVIPIT 2024)

一、会议信息 大会官网&#xff1a;www.mvipit.org 官方邮箱&#xff1a;mvipit163.com 会议出版&#xff1a;IEEE CPS 出版 会议检索&#xff1a;EI & Scopus 检索 会议地点&#xff1a;河北张家口 会议时间&#xff1a;2024 年 9 月 13 日-9 月 15 日 二、征稿主题…

Mysql解忧杂货铺

欢迎来到一夜看尽长安花 博客&#xff0c;您的点赞和收藏是我持续发文的动力 对于文章中出现的任何错误请大家批评指出&#xff0c;一定及时修改。有任何想要讨论的问题可联系我&#xff1a;3329759426qq.com 。发布文章的风格因专栏而异&#xff0c;均自成体系&#xff0c;不足…

【python虚拟环境管理】【mac m3】 使用pipx安装poetry

文章目录 一. 安装 pipx二. 安装Poetry1. 安装2. advanced 操作 官网文档&#xff1a;https://python-poetry.org/docs/ pipx介绍文档&#xff1a;https://blog.51cto.com/u_15064632/2570626 一. 安装 pipx pipx 用于全局安装 Python 命令行应用程序&#xff0c;同时在虚拟环…

注册安全分析报告:OneApm

前言 由于网站注册入口容易被黑客攻击&#xff0c;存在如下安全问题&#xff1a; 暴力破解密码&#xff0c;造成用户信息泄露短信盗刷的安全问题&#xff0c;影响业务及导致用户投诉带来经济损失&#xff0c;尤其是后付费客户&#xff0c;风险巨大&#xff0c;造成亏损无底洞 …

【大型实战】企业网络实验(华为核心交换、ESXI7.0vmware虚拟机、DHCP中继、服务端网络及用户端网络配置)

需求 实验 vmware网络配置&#xff08;企业内部一般为ESXI&#xff09; 这样服务器虚拟机使用192.168.200.X网段才能与用户侧互通 vmware虚拟机配置&#xff08;DHCP服务器网络配置&#xff09; 打开网络管理页面 nmtui重置一下网络连接&#xff08;重启网卡&#xff09; …