如何学习理解Redux Middleware
Redux中的middleware其实就像是给你提供一个在action发出到实际reducer执行之前处理一些事情的机会。可以允许我们添加自己的逻辑在这段当中。它提供的是位于 action 被发起之后,到达 reducer 之前的扩展点。
加入middleware后,整个数据的流动如下图所示:

举个简单的例子,我们使用middleware将每次action的执行详细信息都打出来。就用官方demo中的todoApp来举例,我们先实现一个简单的reducer用来添加一个todo:
- const todoApp = (state = {todo: []}, action) => {
- if (action.type === ‘addTodo’) {
- state.todo = […state.todo, action.value]
- }
- return state
- }
然后再补上其他逻辑测试,用最原始的方法实现将每次action的执行信息log出来:
- const redux = require(‘redux’)
- const todoApp = (state = {todo: []}, action) => {
- if (action.type === ‘addTodo’) {
- state.todo = […state.todo, action.value]
- }
- return state
- }
- let store = redux.createStore(todoApp);
- const action = {
- type: ‘addTodo’,
- value: ‘todo’,
- }
- console.log(‘state: ‘, store.getState());
- console.log(‘action: ‘, action);
- store.dispatch(action)
- console.log(‘next state: ‘, store.getState())
如果不出什么意外的话,我们这段代码应该会成功运行,并且将这段log出这个action的运行情况, 如下图:

接下来我们将log这件事尝试使用redux的middleware来完成。
首先,根据我们之前的了解,middleware其实是一段在action到reducer之间的处理逻辑。我们都知道,标准的一个redux发送一个action是调用store自身的dispatch方法。那么,我们想要在一个action到达reducer之前去做些处理的话,最好的地方应该就是尝试将store的dispatch替换为我们自己的,在其中加上我们的处理逻辑,例如打印log这件事。
- let store = redux.createStore(todoApp);
- const next = store.dispatch;
- const dispatchWithLog = (action) => {
- console.log(‘state: ‘, store.getState());
- console.log(‘action: ‘, action);
- next(action);
- console.log(‘next state: ‘, store.getState());
- }
- store.dispatch = dispatchWithLog;
我们将默认store的dispatch替换为自己的dispatchWithLog, 通过这种方式,完成了我们的需求,只要任何地方调用了store的diapatch去发送新的action, 我们都能讲其log出来,这个看起来已经有一点middleware的意思了。
虽然上面已经可以解决问题了,并且已经有点middleware的意思了,但是还有一点硬伤就是,需求多了就比较难搞了,例如就像官方上既需要log又需要Crash Reporting, 再通过这种方式去处理就显得很不优雅。Crash Reporting的middle的一个简单实现如下:
- const next1 = store.dispatch;
- const dispatchWithCreshReporting = (action) => {
- try {
- next1(action);
- } catch (err) {
- console.error(err);
- }
- }
- store.dispatch = dispatchWithCreshReporting;
当然,redux本身给我们提供了包装过后的工具方法来专门应用middleware。其中也不是简单粗暴的替换store上的dispatch了。这个方法即为applyMiddleware。
官方的doc也给出了一个关于applyMiddleware的一个简单粗暴的直接替换dispatch的一个示例,如下:
- function applyMiddlewareByMonkeypatching(store, middlewares) {
- middlewares = middlewares.slice()
- middlewares.reverse()
-
- // Transform dispatch function with each middleware.
- middlewares.forEach(middleware =>
- store.dispatch = middleware(store)
- )
- }
关于先逆序middlewares再进行替换,这里主要是为了,让middleware的执行顺序按照我么传给他的array顺序来进行。就像我们上面直接替换的那个例子,越往后面进行替换dispatch的在执行过程中先运行。
当然,官放的具体实现中不是这么简单粗暴的直接替换的方式,因为一来不够优雅,这种方式在链式的调用过程中有可能出现问题。比如某一个middleware并不是同步执行的,这样在进行store.dispatch = middleware(store)就有可能到下一个middleware时,store.dispatch还没有被替换。因此,官方的middleware是接受一个next的参数来,来拿到dispatch,并不是直接从store上对dispatch进行操作的。
一般一个标准的middleware是这个样子的,我们使用最初的log的那个middleware来举例,让它接受一个next(就是一个下一个的dispatch方法),再返回一个dispatch方法。
- function logger(store) {
- return function(next) {
- return function(action) {
- console.log(‘state: ‘, store.getState());
- console.log(‘action: ‘, action);
- let result = next(action);
- console.log(‘next state: ‘, store.getState());
- return result;
- }
- }
- }
- function creshReporting(store) {
- return function(next) {
- return function(action) {
- try {
- return next(action);
- } catch (err) {
- console.error(err);
- return next;
- }
- }
- }
- }
然后假设我们在apply时这样应用一下:
- function applyMiddleware(store, middlewares = [logger, crashReporting]) {
- middlewares = middlewares.slice()
- middlewares.reverse()
- let dispatch = store.dispatch
- middlewares.forEach(middleware =>
- dispatch = middleware(store)(dispatch)
- )
- return Object.assign({}, store, { dispatch })
- }
这样就能够进行优雅的链式调用了。并且用上ES6箭头函数后,这样写出来会更加的优雅:
- const logger = store => next => action => {
- console.log(‘state: ‘, store.getState());
- console.log(‘action: ‘, action);
- let result = next(action);
- console.log(‘next state: ‘, store.getState());
- return result;
- }
最后,其实redux middleware使用起来其实是非常的方便的,只需要记住applyMiddleware这个API即可。即const store = createStore(reducer, applyMiddleware(middlewares))
分享完毕,喜欢搭建可以喜欢蜘蛛表格小编的分享,以后还会给大家分享更多内容
如何学习理解Redux Middleware的更多相关文章
- redux middleware 的理解
前言 这几天看了redux middleware的运用与实现原理,写了一个百度搜索的demo,实现了类似redux-thunk和redux-logger中间件的功能. 项目地址:https://git ...
- 理解Redux以及如何在项目中的使用
今天我们来聊聊Redux,这篇文章是一个进阶的文章,建议大家先对redux的基础有一定的了解,在这里给大家推荐一下阮一峰老师的文章: http://www.ruanyifeng.com/blog/20 ...
- 3.3 理解 Redux 中间件(转)
这一小节会讲解 redux 中间件的原理,为下一节讲解 redux 异步 action 做铺垫,主要内容为: Redux 中间件是什么 使用 Redux 中间件 logger 中间件结构分析 appl ...
- 理解 Redux 中间件机制
Redux 的 action 是一个 JS 对象,它表明了如何对 store 进行修改.但是 Redux 的中间件机制使action creator 不光可以返回 action 对象,也可以返回 ac ...
- 全面学习理解TLB(Translation Look-aside Buffer)地址变换高速缓存
全面学习理解TLB(Translation Look-aside Buffer)地址变换高速缓存 前言: 本文学习思路是:存在缘由 --> 存在好处 --> 定义性质 --> 具 ...
- 轻松理解Redux原理及工作流程
轻松理解Redux原理及工作流程 Redux由Dan Abramov在2015年创建的科技术语.是受2014年Facebook的Flux架构以及函数式编程语言Elm启发.很快,Redux因其简单易学体 ...
- MLT的学习理解
MLT的学习理解 MLT是一个开源的多媒体库,我们的音视频编辑工具,是使用它作为底层支持,某司的'快剪辑'pc版和安卓版,也是用的它. MLT简介 它的GitHub地址,这个库比较老了,现在只有一个作 ...
- 菜鸟之路——机器学习之SVM分类器学习理解以及Python实现
SVM分类器里面的东西好多呀,碾压前两个.怪不得称之为深度学习出现之前表现最好的算法. 今天学到的也应该只是冰山一角,懂了SVM的一些原理.还得继续深入学习理解呢. 一些关键词: 超平面(hyper ...
- batch normalization学习理解笔记
batch normalization学习理解笔记 最近在Andrew Ng课程中学到了Batch Normalization相关内容,通过查阅资料和原始paper,基本上弄懂了一些算法的细节部分,现 ...
随机推荐
- Webstorm 配置 Less编译
配置less编译
- linux ioctl 接口
大部分驱动需要 -- 除了读写设备的能力 -- 通过设备驱动进行各种硬件控制的能力. 大 部分设备可进行超出简单的数据传输之外的操作; 用户空间必须常常能够请求, 例如, 设 备锁上它的门, 弹出它的 ...
- linux获知当前时间
内核代码能一直获取一个当前时间的表示, 通过查看 jifies 的值. 常常地, 这个值只代 表从最后一次启动以来的时间, 这个事实对驱动来说无关, 因为它的生命周期受限于系统 的 uptime. 如 ...
- js中的克隆
1.如果克隆对象是基本类型,直接复制就可以 <script type="text/javascript"> var str1 = 'abc' var str2 = st ...
- ASP.NET MVC4.0+EF+LINQ+bui+bootstrap+网站+角色权限管理系统(3)
接下来完成用户.角色的增删查改,以及用户角色.权限的设置 对用户表.角色表做了一些扩展如下[可以更加自己需要增减字段] 相应的M_UserProfile.cs.M_Roles.cs进行扩展 using ...
- java打包上传服务器的一些命令
Maven下package打包成jar包和war包,都在target目录下 其中War包扔在tomcat的webapps目录下.随tomcat启动自行启动 运行jar包命令. nohup java - ...
- CodeForces Goodbye 2017
传送门 A - New Year and Counting Cards •题意 有n张牌,正面有字母,反面有数字 其中元音字母$a,e,o,i,u$的另一面必须对应$0,2,4,6,8$的偶数 其他字 ...
- ie6,7不支持display:inline-block;
解决方案: display:inline-block; *display:inline;*zoom:1; ie6:* _ ,ie7:*
- ELK系统分析nginx日志
一.nginx nginx 服务器日志的log_format格式: log_format main '$remote_addr - $remote_user [$time_local] "$ ...
- 33.python之操作系统,进程,线程
转载:https://www.cnblogs.com/yuanchenqi/articles/6248025.html 操作系统 一 为什么要有操作系统? 现代计算机系统是由一个或者多个处理器,主存, ...