理解 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中. 所谓中间 ...
随机推荐
- py02_02:pyc的解释
1. Python是一门解释型语言吗? 我初学Python时,听到的关于Python的第一句话就是,Python是一门解释性语言,我就这样一直相信下去,直到发现了*.pyc文件的存在.如果是解释型语言 ...
- Filezilla Xshell SecureFX Win10等无法拖放文件(本地或线上)解决办法
一.win10系统Filezilla Xshell SecureFX等无法拖放文件到线上服务器解决办法: 1.按窗口键+R,打开“运行”对话框:输入regedit回车 2.在注册表编辑器地址栏输入以下 ...
- 将List 分成n个长度由调用者指定的子List
public static void main(String[] args) { List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8); ...
- 关于sql更新最后一个逗号的去除或则最后的and的去除
去除最后的逗号substr_replace($update_sql ,"",-1);去除最后的and substr_replace($update_sql ,"" ...
- jacascript 滚动scroll
滚动 scroll scrollHeight 表示元素的总高度,包括由于溢出而无法展示在网页的不可见部分: scrollWidth 表示元素的总宽度,包括由于溢出而无法展示在网页的不可见部分: 没有滚 ...
- goweb-访问数据库
访问数据库 对许多Web应用程序而言,数据库都是其核心所在.数据库几乎可以用来存储你想查询和修改的任何信息,比如用户信息.产品目录或者新闻列表等. Go没有内置的驱动支持任何的数据库,但是Go定义了d ...
- Android之布局Application类
转载:https://blog.csdn.net/pi9nc/article/details/11200969 一 Application源码描述 * Base class for maintaini ...
- 在Myeclipse10中配置tomcat后新建工程
1.配置tomcat6.0 这里不在细说,和eclipse配置是一模一样的. 2.新建动态网站项目 3.配置显示服务器窗口 4.把项目与服务器链接 5.运行项目
- 吴裕雄--天生自然python学习笔记:python 用pygame模块处理音频文件
除了对图片. Word 等普通格式的文件进行处理外, Python 还有强大的多媒体文件操作能力,如对音频.视频 文件的操作 . 如果要播放音乐,我们可以用 pygame 包中的 mixer 对 象. ...
- 使用idea创建spring mvc项目图文教程
使用idea创建spring mvc项目图文教程 前言: 使用惯了eclipse的朋友,如果刚换成了idea或许有些不习惯.但是使用idea之后,就会love上idea了.本文将通过图文讲解怎么通过i ...