applyMiddleware源码中的闭包
闭包都是个老掉牙的话题了,这次又提起,是因为重看Redux源码时发现了applyMiddleware里的用法很巧妙。我们先看一个简单的例子。
var a = (num) => num + 1
var b = {
name: (num) => a(num)
} a = (num) => num + 5 console.log(b.name(3))
打印结果是4还是8呢?
对象b有一个属性name。name是一个方法,函数体里使用了函数a,a是全局作用域的变量,之后a修改了。答案是8。我们不是在作用域里取到变量的值,而是在作用域所对应的执行上下文取到变量的值,并且可能同样的作用域,相同的变量取到的值是不同的。 可以看看这篇文章系列。
接下来看我们的applyMiddleware源码。
export default function applyMiddleware(...middlewares) {
return (createStore) => (reducer, preloadedState, enhancer) => {
const store = createStore(reducer, preloadedState, enhancer)
let dispatch = store.dispatch
let chain = []
const middlewareAPI = {
getState: store.getState,
dispatch: (action) => dispatch(action)
}
chain = middlewares.map(middleware => middleware(middlewareAPI))
dispatch = compose(...chain)(store.dispatch)
return {
...store,
dispatch
}
}
}
一个比较关键的的地方是变量middlewareAPI ,它是一个对象,对象有方法dispatch,该方法内部调用了外部的dispatch。接下来在数组map方法里,该对象作为实参传递。
我们看thunk中间件源码
export default function thunkMiddleware({ dispatch, getState }) {
return next => action =>
typeof action === 'function' ?
action(dispatch, getState) :
next(action);
}
middlewareAPI 传递过来的dispatch一直到判断了action是function的时候才进行传递使用,这个时候的dispatch其实是已经增强的dispatch了,即dispatch = compose(...chain)(store.dispatch)这个dispatch了。
总结起来就是中间件的形参next接受的是原始store.dispatch,而thunkMiddleware({ dispatch, getState })或者说是middleware(middlewareAPI)里的dispatch是增强后的dispatch = compose(...chain)(store.dispatch)这个dispatch了
applyMiddleware源码中的闭包的更多相关文章
- redux:applyMiddleware源码解读
前言: 笔者之前也有一篇关于applyMiddleware的总结.是applyMiddleware的浅析. 现在阅读了一下redux的源码.下面说说我的理解. 概要源码: step 1: apply ...
- Android 源码中的设计模式
最近看了一些android的源码,发现设计模式无处不在啊!感觉有点乱,于是决定要把设计模式好好梳理一下,于是有了这篇文章. 面向对象的六大原则 单一职责原则 所谓职责是指类变化的原因.如果一个类有多于 ...
- jquery源码中noConflict(防止$和jQuery的命名冲突)的实现原理
jquery源码中noConflict(防止$和jQuery的命名冲突)的实现原理 最近在看jquery源码分析的视频教学,希望将视频中学到的知识用博客记录下来,更希望对有同样对jquery源码有困惑 ...
- Python源码中的PyCodeObject
1.Python程序的执行过程 Python解释器(interpreter)在执行任何一个Python程序文件时,首先进行的动作都是先对文件中的Python源代码进行编译,编译的主要结果是产生的一组P ...
- 从express源码中探析其路由机制
引言 在web开发中,一个简化的处理流程就是:客户端发起请求,然后服务端进行处理,最后返回相关数据.不管对于哪种语言哪种框架,除去细节的处理,简化后的模型都是一样的.客户端要发起请求,首先需要一个标识 ...
- Android 网络框架之Retrofit2使用详解及从源码中解析原理
就目前来说Retrofit2使用的已相当的广泛,那么我们先来了解下两个问题: 1 . 什么是Retrofit? Retrofit是针对于Android/Java的.基于okHttp的.一种轻量级且安全 ...
- Eclipse与Android源码中ProGuard工具的使用
由于工作需要,这两天和同事在研究android下面的ProGuard工具的使用,通过查看android官网对该工具的介绍以及网络上其它相关资料,再加上自己的亲手实践,算是有了一个基本了解.下面将自己的 ...
- String源码中的"avoid getfield opcode"
引言: 之前一篇文章梳理了String的不变性原则,还提到了一段源码中注释"avoid getfield opcode",当时通过查阅资料发现,这是为了防止 getfield(获取 ...
- android源码中修改wifi热点默认始终开启
在项目\frameworks\base\wifi\java\android\net\wifi\WifiStateMachine.java里面,有如下的代码,是设置wifi热点保持状态的:如下: pri ...
随机推荐
- MyBatis与Hibernate
Mybatis和hibernate不同,它不完全是一个ORM框架,因为MyBatis需要程序员自己编写Sql语句.mybatis可以通过XML或注解方式灵活配置要运行的sql语句,并将java对象和s ...
- C++ 系列:extern
extern 作用1:声明外部变量现代编译器一般采用按文件编译的方式,因此在编译时,各个文件中定义的全局变量是互相透明的,也就是说,在编译时,全局变量的可见域限制在文件内部. 例1:创建一个工程,里面 ...
- Android开发 SpannableString开发详解
前言 SpannableString,是google提供用来处理富文本的功能类.支持很多文本内容的效果变化.另外,它也是Android实现富文本编辑器的关键. 关键API详解 String conte ...
- CF1158F Density of subarrays
CF1158F Density of subarrays 首先可以发现,有值的p最大是n/c 对于密度为p,每个数至少出现c次,且其实是每出现c个数,就分成一段,这样贪心就得到了p %ywy n/c ...
- samba初级使用记录
首先安利一下什么是samba: Samba是在Linux和UNIX系统上实现SMB协议的一个免费软件,由服务器及客户端程序构成.SMB(Server Messages Block,信息服务块)是一种在 ...
- java面向对象特征 — 一句话概括
java基础学习总结之基本特征,最开始学习的时候,是形而上的理解,用了3年多,再回头看,理解起来颇为顺理成章 语言学习大概就是这样一种规律,学习,不甚解,应用,应用,渐深入人心,回头一看,恍然一悟 最 ...
- Nopi 导出设置行高
1.导出excel行显示不完整数据客户不满意,需要我们处理 ; rowNum <= sheet.LastRowNum; rowNum++) { HSSFRow currentRow = shee ...
- Ionic 生成icon图标
1.直接切换到项目跟目录 运行以下命令 备注:运行第一次ionic rescoures 后自动生成文件夹rescoures ,让后帮你自己的icon.png 文件放进入就ok ,在次运行ionic r ...
- 机器学习实战之Apriori
机器学习实战之Apriori 1. 关联分析 1.1 定义 关联分析是一种在大规模数据上寻找物品间隐含关系的一种任务.这种关系有2种形式:频繁项集和关联规则. (1) 频繁项集(freq ...
- JEECMS 系统权限设计
1.用户校验. 登录校验主要围绕着用户后台登陆的url拦截 a.围绕着用户登录过程中设计到两张用户表 jc_user:存储着用户的基本信息 jo_user:存储着用户登录.注册.更新时间及用户密码信息 ...