理解 Redux 中间件机制
Redux 的 action 是一个 JS 对象,它表明了如何对 store 进行修改。但是 Redux 的中间件机制使action creator 不光可以返回 action 对象,也可以返回 action 函数, middleware 会拦截自己感兴趣的 action 类型,然后进行某些共性的操作。比如在拉取服务器数据时,如果没有中间件机制,我们可能需要首先请求数据,数据到达后,将数据给 action creator得到一个 action 对象,再 dispatch action;有了redux-promise 中间件后,就可以将数据请求的逻辑直接放在 action creator 中,然后中间件自动拦截Promise类型的 action,等待 action fulfilled 之后,再 dispatch 最终的 action 对象
一、middleware
middleware 相当于是对 store.dispatch()函数的包装,一些针对特定action的处理,或者对所有action都进行的处理放进middleware中进行。
middleware使 action creator 不光可以返回 action 对象,也可以返回 action 函数,因为 middleware 会拦截自己感兴趣的 action ,然后对那个 action 进行某些共性的操作,比如调用 Ajax调用。
middleware可以有多个,每个 middleware 类似以下形式:
1 |
const oneMiddleware = ({ dispatch, getState} ) => (next) => (action) => {
|
二、 applyMiddleware 源码解析
下面是redux/lib/index.js中applyMiddleware的源码
1 |
function applyMiddleware() {
|
总结三个要点:
- 当使用了applyMiddleware时,实际是
applyMiddleware(...middleware)(createStore)(reducers, preloadedState)这样的调用方式。将 createStore 作为参数传入,而不是直接对 store 应用middleware,主要是为了防止对 store 引用多次相同的middleware - 不能在创建时刻调用dispatch,因为这时如果非要调用 dispatch,那么只能调用 createStore 的 dispatch,不会经过 middleware。所以源码在这步干脆就把 dispatch 替换成了一个会抛出错误的函数。
- 使用 compose 函数将多个 middleware 变为一层包一层的洋葱式的执行方式,洋葱的核心是 createStore 的 dispatch
下面是compose函数的源码
1 |
// compose.apply(undefined, chain)(store.dispatch); |
这里有两个要点:
- compose 函数返回的是一个以 store.dispatch 函数为参数的函数,这步就是为洋葱式的执行结构填上核心
- compose 函数的核心是 Array.prototype.reduce 的应用,它的作用是对数组中的每个元素(从左到右)应用某个函数,最后返回一个结果
reduce 函数具体可以看下面的例子:
1 |
const chain1 = (next) => (action) => {
|
总之最后 applyMiddleware函数最后返回的是一个 dispatch 被 middleware 包裹后的 store。这样当dispatch 一个 action时,action会先通过每个 middleware,middleware 可以根据 action的内容或者类型(比如是否为function)等信息来拦截自己感兴趣的 action,然后再对这个 action 特殊处理。
三、 redux-promise 源码解读
1 |
function promiseMiddleware(_ref) {
|
以上就是 redux-promise 的源码,它会拦截是 Promise 对象 或者 payload 属性是promise 对象的action。看上去还是非常简单的。
但是这里有一个要点,就是在 applyMiddleware 中,有一个用 middleware 函数数组 构建 chain 函数数组的过程,为了防止 middleware 在构建过程中调用 dispatch ,它传递的 dispatch 函数,函数体是这样的
1 |
var _dispatch = function dispatch() {
|
==那么为什么在构建时,middleware 调用 dispatch 会出错,在构建之后 middleware 调用 dispatch 不会出错呢?==
我们知道函数是引用传递的,所以说在 promiseMiddleware中的 var dispatch = _ref.dispatch 中存储的是
1 |
function dispatch() {
|
这个函数的引用,而在构建过程时,一调用 dispatch 函数,就会调用 _dispatch 函数,然后就报错了。
但是 applyMiddleware 在构建完成后有这样一步操作
1 |
_dispatch = compose.apply(undefined, chain)(store.dispatch); |
这样就覆盖了之前的只会报错的 _dispatch,从而在 middleware 中可以正常的调用 dispatch了。
另外从上面可以看出,==在 middleware 中调用的 dispatch 不是 createStore 的 dispatch,而是经过 middleware 包装的 dispatch==。
理解 Redux 中间件机制的更多相关文章
- 3.3 理解 Redux 中间件(转)
这一小节会讲解 redux 中间件的原理,为下一节讲解 redux 异步 action 做铺垫,主要内容为: Redux 中间件是什么 使用 Redux 中间件 logger 中间件结构分析 appl ...
- redux深入理解之中间件(middleware)
理解reduce函数 reduce() 方法接收一个函数作为累加器(accumulator),数组中的每个值(从左到右)开始缩减,最终为一个值. arr.reduce([callback, initi ...
- 理解 Redux 的中间件
将该思想抽象出来,其实和 Redux 就无关了.问题变成,怎样实现在截获函数的执行,以在其执行前后添加自己的逻辑. 为了演示,我们准备如下的示例代码来模拟 Redux dispatch action ...
- DDD实践案例:引入事件驱动与中间件机制来实现后台管理功能
DDD实践案例:引入事件驱动与中间件机制来实现后台管理功能 一.引言 在当前的电子商务平台中,用户下完订单之后,然后店家会在后台看到客户下的订单,然后店家可以对客户的订单进行发货操作.此时客户会在自己 ...
- 【React全家桶入门之十三】Redux中间件与异步action
在上一篇中我们了解到,更新Redux中状态的流程是这种:action -> reducer -> new state. 文中也讲到.action是一个普通的javascript对象.red ...
- 理解Redux以及如何在项目中的使用
今天我们来聊聊Redux,这篇文章是一个进阶的文章,建议大家先对redux的基础有一定的了解,在这里给大家推荐一下阮一峰老师的文章: http://www.ruanyifeng.com/blog/20 ...
- 通俗易懂的理解 Redux(知乎)
1. React有props和state: props意味着父级分发下来的属性[父组件的state传递给子组件 子组件使用props获取],state意味着组件内部可以自行管理的状态,并且整个Rea ...
- Redux 中间件与函数式编程
为什么需要中间件 接触过 Express 的同学对"中间件"这个名词应该并不陌生.在 Express 中,中间件就是一些用于定制对特定请求的处理过程的函数.作为中间件的函数是相互独 ...
- Redux:中间件
redux中间件概念 比较容易理解. 在使用redux时,改变store state的一个固定套路是调用store.dispatch(action)方法,将action送到reducer中. 所谓中间 ...
随机推荐
- PAT Advanced 1020 Tree Traversals (25) [⼆叉树的遍历,后序中序转层序]
题目 Suppose that all the keys in a binary tree are distinct positive integers. Given the postorder an ...
- 关于使用静态链表实现一元多项式的相加&&乘积
一元多项式的相加类似于两条链表的合并 当然前提是链表中的幂指数是按顺序排列的 此题中的链表采用的是升序排列,输出也是按升序输出的 #include<stdio.h> #include< ...
- Nginx模块-ngx_http_mirror_module-流量复制
参考1:https://www.cnblogs.com/cjsblog/p/12163207.html Nginx流量复制 需求 将生产环境的流量拷贝到预上线环境或测试环境,这样做有很多好处,比如: ...
- mysql字段修改脚本
-- help_text:帮助说明 -- help_content -- raw USE pro_seal_chip_sell_portal_v1; -- 表修改ALTER TABLE `help_t ...
- [原]UEFI+GPT启动VHD
1. 缘起 2. 创建VHD文件并写入系统镜像到VHD文件 2.1 制作VHD文件 2.1.1 纯界面创建 2.1.2 命令行创建 2.2 把系统镜像写入VHD文件 3. 添加VHD文件到系统引导 3 ...
- springmvc 实现文件上传
1.添加jar包 <dependency> <groupId>commons-io</groupId> <artifactId>commons-io&l ...
- 【Java杂货铺】JVM#Java高墙之GC与内存分配策略
Java与C++之间有一堵由内存动态分配和垃圾回收技术所围成的"高墙",墙外的人想进去,墙外的人想出来.--<深入理解Java虚拟机> 前言 上一章看了高墙的一半,接下 ...
- v-cloak使用
v-cloak:保持和元素实例的关联,直到结束编译后自动消失. v-cloak指令和CSS 规则一起用的时候,能够解决差值表达式闪烁的问题(即:可以隐藏未编译的标签直到实例准备完毕). 就拿上一段代码 ...
- python脚本实现自动安装nginx
本文python脚本实现自动化安装是源码安装.实现任意版本安装,默认版本是1.13.11,也可以更改默认版本,手动配置安装目录. 环境:Ubuntu16.04,python3以上版本,Ubuntu自带 ...
- GSON解译Json为DTO
除了用okhttp网络库外,还用到google的gson库. 1. uti类的对象一般都用懒汉模式.这次gson也是用懒汉模式. public class GsonTools { private st ...