• 前言
    react已经出来很久了,其生态圈之庞大,一锅炖不下!各种react-xx,已让我们不堪重负,github上随便一个demo,引入的模块至少都是五指之数+。看着头疼,嚼之无味……。
    在此建议新学者,可以从基础的核心模块学起,前期不要考虑那些数量繁多的马仔小弟,边学边写,个人感觉前期核心要学的流程大致如下:
    React ——> React + redux + React-redux ——> React + redux + React-redux + React-router ——> React + redux + React-redux + React-router ;
    其它的,看情况学习和了解,我也很菜,以上感悟都是针对初学者,希望可以减少他们在学习过程中接触过多的东西,而影响学习信心和乐趣。
  • 文档
    React小书(作者从无到有,讲述了React的起源,通俗易懂)Note: 第三阶段的文档现在开始收费查看了,不过对于搞前端的人来说不用钱也可以来个亲密接触的(大家自己想办法)
    Redux莞式教程(抛开需求讲实用性都是耍流氓,作者扮演一位PM给我们上了生动的一课,深入浅出,简明扼要)
    React-Router文档(一部中规中矩的翻译之作)

以上是整理的一些说明和文档资料,没有看过的可以去了解一下。下面将开始本文的主题:redux的中间件applyMiddleware。

都说名字越长,越让学者害怕,applyMiddleware的名字看起来就挺吓人,那么为什么会出现中间件,它是做什么的?它为什么叫中间件?为什么说可以用来解决异步dispatch?经过一段时间的了解,让我渐渐明白了它的工作原理,现在让我们带问题,怀着简单,轻松的心态走进applyMiddleware大讲堂:

  1. 为什么会出现中间件?
    我们知道redux的核心,就是控制和管理所有的数据输入输出,因此有了dispatch,由于dispatch是一个很纯的纯函数,就是单纯的派发action来更改数据,其功能简单且固定。
    假如现在产品经理A某有个需求,要求记录每次的dispatch记录,我们怎么办呢?最简单直接的办法就是在每一个dispatch的前面加上:

    console.log('dispatching', action);
    dispatch(action)

    假如又来一个产品B说,我需要记录每次数据出错的原因,我们怎么办呢?然后我们又需要在对每一个dispatch做修改

    try{
    dispatch(action)
    }catch(err){
    console.error('错误报告: ', err)
    }  

    如果我们的程序中有很多的dispatch,我们就需要添加很多的重复代码,虽然编辑器提供批量替换,但这无疑是产生了很多样板代码。
    因为所有的需求都是和dispatch息息相关,所以只要我们把日志放进dispatch函数里,不就好了吗,我们只需要更改dispatch函数,把dispatch进行一层封装。
    大概的封装就是下面这样:

    let next = store.dispatch
    store.dispatch = function dispatchAndLog(action) {
    console.log('dispatching', action)
    next(action)
    }

    Redux把这个封装的入口写成了一个函数,就叫applyMiddleware。
    由此我们明白了applyMiddleware的功能:改造dispatch函数,产生真假dispatch,而中间件就是运行在假真(dispatchAndLog和next)之间的代码。
    这里我们要对applyMiddleware进行一个准确的定义,它只是一个用来加工dispatch的工厂,而要加工什么样的dispatch出来,则需要我们传入对应的中间件函数(比如上例中的dispatchAndLog),下面我们构造一个精简版的applyMiddleware:

    const applyMiddleware = function(middleware){
    let next = store.dispatch;
    store.dispatch = middleware(store)(next); // 这里传入store,是因为中间件中有可能会用到getState获取数据,比如打印当前用户等需求
    } applyMiddleware(dispatchAndLog) 
  2. 中间件的串联融合。
    中间件的功能各不相同,它们都要融入到dispatch中,在派发action的时候,按照顺序一个个的执行,这是一个费脑经的事情。
    假如现在我们有两个中间件 logger和collectError两个中间件函数,那么大概的执行顺序就是 dispatch——>logger改造——>collectError改造。这里我们能看到后面的中间件需要接收到前面改造后的dispatch,
    在前面,我们是直接修改store.dispatch,现在我们换一种写法,让每一个中间件函数,接收一个dispatch,然后返回一个改造后的dispatch,来作为下一个中间件函数的next,以此类推,用ES6的写法大概代码如下:
    const logger = store => next => action => {
    console.log('dispatching', action)
    return next(action)
    } const collectError = store => next => action => {
    try {
    return next(action)
    } catch (err) {
    console.error('Error!', err)
    }
    }

    然后,我们改造一下applyMiddleware,来接收一个middlewares数组:

    function applyMiddleware(middlewares) {
    middlewares = middlewares.slice()
    middlewares.reverse() let dispatch = store.dispatch
    middlewares.forEach(middleware =>
    dispatch = middleware(store)(dispatch)
    )
    return Object.assign({}, store, { dispatch })
    }

    上面的middleware(store)(dispatch) 就相当于是 const logger = store => next => {},这就是构造后的dispatch,继续向下传递。这里middlewares.reverse(),进行数组反转的原因,是最后构造的dispatch,实际上是最先执行的。因为在applyMiddleware串联的时候,每个中间件只是返回一个新的dispatch函数给下一个中间件,实际上这个dispatch并不会执行。只有当我们在程序中通过store.dispatch(action),真正派发的时候,才会执行。而此时的dispatch是最后一个中间件返回的包装函数。然后依次向前递推执行。
    我们拿logger和collectError来说明:

    构造过程:

    let next = store.dispatch;
    let dispatch1 = logger(store)(next);
    // 这时候的console.log('dispatching', action) 是没有执行的 let dispatch2 = collectError(store)(dispatch1);
    // 这时候的console.log('Error!', err) 也是没有执行的 store.dispatch = dispatch2;

    执行过程:

    store.dispatch(action); //假如我们程序中派发了某个action
    
    //相当于是下面这样
    dispatch2(action); //此时执行了 console.log('Error', err) //由于collectError中间件中的next是接收的logger返回函数即dispatch1,所以在开始执行
    dispatch1(action); //此时执行了 console.log('dispatching', action) // 这个例子不太合理,因为错误报告是先 try 的 next(action),但是正常的流程是如此。

    未完待续……

redux中间件的原理——从懵逼到恍然大悟的更多相关文章

  1. redux中间件的原理

    前言react已经出来很久了,其生态圈之庞大,一锅炖不下!各种react-xx,已让我们不堪重负,github上随便一个demo,引入的模块至少都是五指之数+.看着头疼,嚼之无味…….在此建议新学者, ...

  2. 浅谈redux 中间件的原理

    在使用redux管理异步数据流的时候,我们会使用中间件,以redux-thunk中间件为例,我们做一下分析: 首先是构建store,我们需要以下代码进行揉入中间件的类似creatStore函数的构造: ...

  3. 3.3 理解 Redux 中间件(转)

    这一小节会讲解 redux 中间件的原理,为下一节讲解 redux 异步 action 做铺垫,主要内容为: Redux 中间件是什么 使用 Redux 中间件 logger 中间件结构分析 appl ...

  4. redux中间件和redux-thunk实现原理

    redux-thunk这个中间件可以使我们把这样的异步请求或者说复杂的逻辑可以放到action里面去处理,redux-thunk使redux的一个中间件,为什么叫做中间件 我们说中间件,那么肯定是谁和 ...

  5. react+redux教程(七)自定义redux中间件

    今天,我们要讲解的是自定义redux中间件这个知识点.本节内容非常抽象,特别是中间件的定义原理,那多层的函数嵌套和串联,需要极强逻辑思维能力才能完全消化吸收.不过我会多罗嗦几句,所以不用担心. 例子 ...

  6. Express中间件的原理及实现

    在Node开发中免不了要使用框架,比如express.koa.koa2拿使用的最多的express来举例子开发中肯定会用到很多类似于下面的这种代码 var express = require('exp ...

  7. Redux 中间件与函数式编程

    为什么需要中间件 接触过 Express 的同学对"中间件"这个名词应该并不陌生.在 Express 中,中间件就是一些用于定制对特定请求的处理过程的函数.作为中间件的函数是相互独 ...

  8. 理解 Redux 中间件机制

    Redux 的 action 是一个 JS 对象,它表明了如何对 store 进行修改.但是 Redux 的中间件机制使action creator 不光可以返回 action 对象,也可以返回 ac ...

  9. react第十八单元(redux中间件redux-thunk,redux工程目录的样板代码,规范目录结构)

    第十八单元(redux中间件redux-thunk,redux工程目录的样板代码,规范目录结构) #课程目标 中间件:中间件增强redux的可扩展性,实现功能复用的目的. redux-thunk异步逻 ...

随机推荐

  1. 搭建Hadoop平台(新手入门)

    刚刚大学毕业,接触大数据有一年的时间了,把自己的一些学习笔记分享给大家,希望同热爱大数据的伙伴们一起学习,成长! 资料准备: Hadoop-2.7.1下载:http://pan.baidu.com/s ...

  2. JavaScript命令模式

    第一,命令模式: (1)用于消除调用者和接收者之间直接的耦合的模式,并且可以对(调用这个过程进行留痕操作) (2)真的不要乱用这个模式,以为他使你简单调用写法变得非常的复杂和有些难以理解. (3)你的 ...

  3. Akka(32): Http:High-Level-Api,Route exception handling

    Akka-http routing DSL在Route运算中抛出的异常是由内向外浮出的:当内层Route未能捕获异常时,外一层Route会接着尝试捕捉,依次向外扩展.Akka-http提供了Excep ...

  4. Java基础总结--变量、运算符总结

    ---变量基本概述----变量作用:就是用来存储数据变量的声明:变量类型 变量名;变量类型---区分不同类型的数据,变量名--按名访问变量变量名(规则):见名识意,第一个字母小写后面驼峰规则变量的作用 ...

  5. input输入框校验,字母,汉字,数字等

    <!DOCTYPE html><html><head> <meta charset="utf-8"> <meta http-e ...

  6. Repeated Substring Pattern --重复字符串

    Given a non-empty string check if it can be constructed by taking a substring of it and appending mu ...

  7. 【20171025早】alert(1) to win 练习

    本人黑绝楼,自称老黑,男,25岁,曾经在BAT工作过两年,但是一直都是底层人员,整天做重复性工作,甚敢无趣,曾和工作十年之久的同事聊天,发现对方回首过往,生活是寡淡如水,只有机械性工作.旋即老黑毅然决 ...

  8. 数据权限设计——基于EntityFramework的数据权限设计方案:一种设计思路

    前言:“我们有一个订单列表,希望能够根据当前登陆的不同用户看到不同类型的订单数据”.“我们希望不同的用户能看到不同时间段的扫描报表数据”.“我们系统需要不同用户查看不同的生产报表列”.诸如此类,最近经 ...

  9. Android Studio 中修改Apk名称

    修改生成的apk名称,并且使调试时也可以使用. 在app->build.gradle 中增加以下内容: android.applicationVariants.all { variant-> ...

  10. 【ThinkPHP框架学习 】(1) --- thinkphp 3.2.3 验证码验证使用教程分享

    框架版本:ThinkPHP框架     thinkphp 3.2.3 生成验证码 下面是最简单的方式生成验证码: $Verify = new \Think\Verify(); $Verify-> ...