如何学习理解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,基本上弄懂了一些算法的细节部分,现 ...
随机推荐
- Vue与React比较
与React 相似: (1)虚拟DOM(Virtual DOM) 虚拟DOM的诞生是基于:改变真实的DOM状态远比改变一个JS对象的花销要大的多. 虚拟DOM是一个映射真实DOM的JS对象,当有变化产 ...
- HDU1556 Color the ball & 牛客 contest 135-I 区间 [差分标记]
一.差分标记介绍 差分标记用来解决针对区间(修改-查询)的问题,复杂度比线段树要更低.推荐这个博客. 例如,给数组中处于某个区间的数进行加减操作,然后查询某个位置上数的变化值. 二.HDU1556 C ...
- 如何从0到1设计一个MQ消息队列
消息队列作为系统解耦,流量控制的利器,成为分布式系统核心组件之一. 如果你对消息队列背后的实现原理关注不多,其实了解消息队列背后的实现非常重要. 不仅知其然还要知其所以然,这才是一个优秀的工程师需要具 ...
- DEVOPS技术实践_20:串联多个job执行
在jenkins可能会有战役中场景,就是在一个job执行完之后,把这个执行结果作为另一个job的执行条件 比如A执行完,如果A执行成功,则执行B,如果失败则执行C 1 前期准备 A任务 import ...
- 【学习笔鸡】整体二分(P2617 Dynamic Rankings)
[学习笔鸡]整体二分(P2617 Dynamic Rankings) 可以解决一些需要树套树才能解决的问题,但要求询问可以离线. 首先要找到一个具有可二分性的东西,比如区间\(k\)大,就很具有二分性 ...
- $bzoj2560$ 串珠子 容斥+$dp$
正解:容斥+$dp$ 解题报告: 传送门$QwQ$ $umm$虽然题目蛮简练的了但还是有点难理解,,,我再抽象一点儿,就说有$n$个点,点$i$和点$j$之间有$a_{i,j}$条无向边可以连,问有多 ...
- $CF1063B\ Labyrinth$ $01$最短路/$01BFS$
\(Des\) 有一个网格图,上面的格子分为空地和障碍,障碍是不可以走的.现在从给定的起点出发开始到处乱走,最多可以往左走\(l\)次,往右走\(r\)次.求可能到达的点数. \(Sol\) 如果只限 ...
- 从两个角度理解为什么 JS 中没有函数重载
函数重载是指在同一作用域内,可以有一组具有相同函数名,不同参数列表(参数个数.类型.顺序)的函数,这组函数被称为重载函数.重载函数通常用来声明一组功能相似的函数,这样做减少了函数名的数量,避免了名字空 ...
- 「UVA10810」Ultra-QuickSort 解题报告
题面 看不懂?! 大概的意思就是: 给出一个长度为n的序列,然后每次只能交换相邻的两个数,问最小需要几次使序列严格上升 不断读入n,直到n=0结束 思路: 交换相邻的两个数,这不就类似冒泡排序吗?但是 ...
- 1068 万绿丛中一点红 (20分)C语言
对于计算机而言,颜色不过是像素点对应的一个 24 位的数值.现给定一幅分辨率为 M×N 的画,要求你找出万绿丛中的一点红,即有独一无二颜色的那个像素点,并且该点的颜色与其周围 8 个相邻像素的颜色差充 ...