Redux解决了react中出现的多交互、多数据源问题,但是如果有异步操作,或者要对操作进行拦截或者执行后回调就比较麻烦。于是我们需要Redux 中间件。

一、手动增强store.dispatch

我们知道 react-redux的 connect是一个高阶组件,它将组件包装之后拿到一个能够在组件中直接获取 context 的 state 的组件,并且用dispatch监听每一个action:

export const connect = (mapStateToProps, mapDispatchToProps) => (WrappedComponent) => {class Connect extends Component {...let dispatchProps = mapDispatchToProps? mapDispatchToProps(store.dispatch, this.props): {} // 用来 dispatch 的时候获取 store 的 dispatch...    render() {return <WrappedComponent {...this.state.allProps}/>}}return Connect;
}复制代码

如果要增强dispatch,我们可以对其进行重构,直接改写 store 实例中的 dispatch:

let store = createStore(rootReducer);
let dispatch = store.dispatch//拿到dispatch
store.dispatch = function (action) {//对dispatch进行重构console.log('旧状态',store.getState())//1.打印就状态dispatch(action)//2.在执行之前的actionconsole.log('新状态',store.getState())//3.打印新状态
}
复制代码

以上的代码增强了dispatch方法,使执行顺序变成了action->log->reducer->log,执行结果如下:

二、使用redux的applyMiddleware方法增强store.dispatch

redux 提供了类似后端 Express 的中间件概念,本质的目的是提供第三方插件的模式,自定义拦截 action -> reducer 的过程。变为 action -> middlewares -> reducer 。这种机制可以让我们改变数据流,实现如异步 action ,action 过滤,日志输出,异常报告等功能。

官方说明如下:使用中间件扩展增强Redux store上的dispath 方法。因为中间件可能是异步的,所以这应该是定义在组合链中存储增强器。

redux applyMiddleware方法源码

export default function applyMiddleware(...middlewares) {//[middleware1,middleware2]return createStore => (...args) => {const store = createStore(...args)let dispatch = () => {throw new Error(`Dispatching while constructing your middleware is not allowed. ` +`Other middleware would not be applied to this dispatch.`)}const middlewareAPI = {getState: store.getState,dispatch: (...args) => dispatch(...args)}const chain = middlewares.map(middleware => middleware(middlewareAPI))//将middleware放入链式数组dispatch = compose(...chain)(store.dispatch)//依次执行return {// 将增强过的dispatch返回...store,dispatch}}
}
复制代码

applyMiddleware的使用方法,官方文档中给出两种用法:

const store = createStore(reducer, preloadedState, applyMiddleware(...))const store = createStore(reducer, applyMiddleware(...))
复制代码

第二个参数初始化state不是必传的,源码中的createStore方法对参数进行了处理

三、middleware如何工作

redux createStore源码

export default function createStore(reducer, preloadedState, enhancer) {if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') {enhancer = preloadedStatepreloadedState = undefined}if (typeof enhancer !== 'undefined') {if (typeof enhancer !== 'function') {throw new Error('Expected the enhancer to be a function.')}return enhancer(createStore)(reducer, preloadedState)}......    }
复制代码

在createStore方法中判断参数并相应替换,最后createStore代码执行返回的是一个enhancer函数嵌套调用方法,也就是:

const store = applyMiddleware(...)(createStore)(reducer,preloadedState)
复制代码

如图所示:嵌套函数分别传入的createStore和reducer,创建了store,并定义了dispatch方法,并组合成obj传给了logger函数

logger中间件函数接受两个参数 dispatch getState(获取状态 派发动作) 并返回一个新的参数 next,形成了一个dispatch增强函数。小白我对于这个一长串的return理解成如下:

let logger1 = function({dispatch,getState}) {store.dispatch = function(action){console.log('旧状态1',getState())next(action)console.log('新状态1',getState())}
}
复制代码

这已经跟文章开头手动增强store.dispatch的函数十分相近了,主要区别在于next方法。

middleware 通过 next(action) 一层一层处理和传递 action,直到 redux 原生的 dispatch`,这时next为客户端调用的dispatch方法,action为方法传入的actionType:{type:xxx,payload:xxx} 咳,代码要优雅,小白我理解了就要按照官方的来,正确的middleWare一样定义格式如下:

let logger = ({dispatch,getState}) => next => action =>{console.log('旧状态1',getState())next(action)//dispatch(action)console.log('新状态1',getState())
}
复制代码

中间件的实现和洋葱模型很像,先触发logger第一层,再触发dispatch事件,最后再从logger函数出来。

四、compose实现链式调用

实现多个中间件先后调用的关键是compose函数

redux compose源码链接

export default function compose(...funcs) {if (funcs.length === 0) {return arg => arg}if (funcs.length === 1) {return funcs[0]}return funcs.reduce((a, b) => (...args) => a(b(...args)))
}
复制代码

源码很精简,理解有点复杂。其实是使用reduce不断将最右先调动函数的结果返回给后调用的函数。

举个栗子,

function add1(str){return str+1;
}
function add2(str){return str+2;
}
function add3(str){return str+3;
}let add = compose(add3,add2,add1);
let r = add("啊哈哈哈")//啊哈哈哈123
复制代码

在这段代码中,compose函数执行顺序为add1->add2->add3,并将结果作为参数传给下一个函数。

在redux中当新 dispatch 执行时,[f1, f2, ... , fx, ..., fn],从右到左依次执行。

dispatch = f1(f2(f3(store.dispatch))))
复制代码

如图所示,从右至左执行logger2,logger1。logger2返回的代码作为参数传给logger1的next参数。按照图上1->2(执行下一个middleware)->3->4(触发redux 原生的 dispatch方法)->5->6 完成

链式middleware流程图如下

五、异步操作

很多时候,我们需要异步操作。用户触发第一个dispatch事件的action,需要发送第二个action。或者根据返回的根据发送第二个处理请求。

解决异步操作的方法:

(1)redux函数的参数是dispatch和getState,把返回的obj改成返回一个异步函数。

(2)异步操作结束之后,再发出一个 Action。

function incrementAsync() {return dispatch => {setTimeout(() => {// Yay! Can invoke sync or async actions with `dispatch`dispatch(increment());}, 1000);};
}
复制代码

这样子能理想得解决异步操作,而store.dispatch方法正常情况下,参数只能是对象,不能是函数。

这个时候可以引入redux-thunk

Redux Thunk middleware allows you to write action creators that return a function instead of an action. The thunk can be used to delay the dispatch of an action, or to dispatch only if a certain condition is met. The inner function receives the store methods dispatch and getState as parameters.

redux-thunk实现源码:

function createThunkMiddleware(extraArgument) {return ({ dispatch, getState }) => next => action => {if (typeof action === 'function') {return action(dispatch, getState, extraArgument);}return next(action);};
}const thunk = createThunkMiddleware();
thunk.withExtraArgument = createThunkMiddleware;export default thunk;
复制代码

redux-thunk 做的事情就是判断 action 类型是否是函数,若是,则执行 action,若不是,则继续传递 action 到下个 middleware。

运用方法:

let store = createStore(rootReducer,applyMiddleware(thunk,logger1,logger2)
)
复制代码

如图所示,当store.dispatch运行到thunk中间件,发现返回的是一个function,则执行返回的函数,并返回,重新派发dispatch

因此使用redux-thunk,改造store.dispatch。可以实现异步方法

还有如 redux-promise redux-saga也可以解决异步的问题

作者:圆儿圈圈
链接:https://juejin.im/post/5b792b8a51882542e441f376
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

喵了个咪!redux middleware居然如此简单相关推荐

  1. 喵了个咪!redux middleware居然如此简单!

    Redux解决了react中出现的多交互.多数据源问题,但是如果有异步操作,或者要对操作进行拦截或者执行后回调就比较麻烦.于是我们需要Redux 中间件. 一.手动增强store.dispatch 我 ...

  2. 喵了个咪 官网网站,重磅发布~~~www.miaolegemi.world

    喵了个咪,致力于打造一个面向年轻人的娱乐互动平台!现有[段子.小游戏.实用工具.唐诗.宋词]等板块,持续更新中..... 重要的事情说三遍! 喵了个咪,官网网址:https://www.miaoleg ...

  3. 利用Arduino对路由器进行调试,居然这么简单!

    本文讲的是利用Arduino对路由器进行调试,居然这么简单!, 在生产嵌入式系统,如路由器或网络摄像头时,制造商就已预留了一些调试端口.不过对于一般的用户来说,这些预留的调试端口显然是用不到的,因为它 ...

  4. 梦幻新诛仙微信绑定没有服务器,独乐乐不如众乐乐,在《梦幻新诛仙》里交朋友居然这么简单?...

    原标题:独乐乐不如众乐乐,在<梦幻新诛仙>里交朋友居然这么简单? 说到社交游戏,可能大家对于这个概念并不是很能理解,但要说到偷菜肯定是家喻户晓的.这也是游戏里最早期的社交方式.随着游戏行业 ...

  5. 视频直播APP源码在安卓中推送SDK集成居然如此简单!

    视频直播APP源码在安卓中推送SDK集成居然如此简单! 思维导图 详细步骤 下载 demo 我的师傅大鸟哥告诉我,集成各类 SDK 的第一步骤都是下载个 Demo,先把 Demo 跑起来看看是什么鬼. ...

  6. 云时代下,医药行业管理居然这么简单

    摘要:为了持续打造核心竞争力,英克康健联合华为云,基于云数据库RDS for PostgreSQL全新打造了一个高性能.大容量.高可用的SaaS医药管理系统,助力万千药企业务迈上新台阶. 本文分享自华 ...

  7. redux middleware 源码分析

    原文链接 middleware 的由来 在业务中需要打印每一个 action 信息来调试,又或者希望 dispatch 或 reducer 拥有异步请求的功能.面对这些场景时,一个个修改 dispat ...

  8. koa/redux middleware 深入解析

    middleware 对于现有的一些框架比如koa,express,redux,都需要对数据流进行一些处理,比如koa,express的请求数据处理,包括json.stringify,logger,或 ...

  9. 简单、好懂的 Redux middleware 原理

    It provides a third-party extension point between dispatching an action, and the moment it reaches t ...

最新文章

  1. Android隐藏状态栏和标题栏,相当于全屏效果
  2. 小余学调度:学习记录(2021.9.13-2021.9.19)母线操作和线路操作
  3. eslint 禁用命令
  4. F. Cowmpany Cowmpensation(树形dp + 拉格朗日插值)
  5. 非对称加密算法 --- RSA签名算法
  6. Java 主流垃圾收集器
  7. linux下重新启动oracle
  8. MATLAB中如何删除坐标上已画出的内容
  9. Nginx: error while loading shared libraries: libpcre.so.1解决
  10. 22年前,100万买入谷歌原始股,奥尼尔的股份如今市值多少?
  11. android imageview scaletype 按钮状态,Android ImageView 之 ScaleType 详解
  12. SSH网上商城:回首网上商城
  13. 摘抄 ander图片上传
  14. 《计算机网络》谢希仁第七版课后答案完整版
  15. SpringBoot非官方教程 | 第二十五篇:2小时学会springboot
  16. 基于FPGA的Yolov4 tiny目标检测网络加速器
  17. 如何让IE11自动下载安装ActiveX插件并使用网页VLC播放视频
  18. Unexpected Error 0x8ffe2740 Occured
  19. BIEE 11g 安装
  20. 4800余网站涉“黄”被封 新浪搜狐腾讯关栏目

热门文章

  1. 微信小程序-仿朋友圈发布动态(包括后端上传图片)
  2. 如何安装JDK,最详细JDK安装教程
  3. 没花一分钱的我竟然收到的JetBrains IDEA官方免费赠送一年的Licence
  4. snprintf 函数用法
  5. Android裁剪图片为圆形图片
  6. linux 编辑list文件,Linux常用命令(非常详细!)
  7. Mysql关键字执行顺序-深入解析
  8. 如何在linux系统安装igh,Linux下IGH Ethercat Master安装
  9. 12个前端必会 H5 问题及解决方法
  10. 刘晓艳的作文笔记 自己构造模板 写作技巧 同义替换