前传  中间件的由来

  redux的操作的过程,用户操作的时候,我们通过dispatch分发一个action,纯函数reducer检测到该操作,并根据action的type属性,进行相应的运算,返回state,然后更新view。

  但是一个很重要的问题,reducer对于action会立即进行运算,并返回state,如果我们的操作是要获取服务端的数据,需要调用接口类似的异步操作呢?很明显这样操作不行。所以,middleware中间件诞生了,中间件就是处理reducer处理不了的问题,对reducer做一个补充,配合。

  我们就以使用中间件来解决异步问题为例来说,中间件顾名思义,就是作为一个流程的一个中间处理程序存在,它是放到一个流程的中的。问题是在处理一部问题,我们把他放哪的问题

    a、action只是一个跑腿的,把操作的相关数据带到reducer;

    b、reducer只是个干活的,纯函数,计算一下嘛,返回新的数据,但是,异步操作它搞不了;

    c、view,理论上这或者是显示的,最好不要有太多的逻辑,中间件肯定不能放;

    d、剩下的就是把action分发到reducer的dispatch了,我们可以在分发的时候做点手脚,其实就是对dispatch的重写或者是扩展。

看看applyMiddleware

  中间件知道放在哪了,我们看看实现中间件的重要api ----- applyMiddleware 的源码

  1. function applyMiddleware() {
     
  2. for (var _len = arguments.length, middlewares = Array(_len), _key = 0;
       _key < _len; _key++) {
  3.   middlewares[_key] = arguments[_key];
  4. }
  5.  
  6. return function (createStore) { // 以下称这个方法为func1
  7. return function () { // 以下称这个方法为func2
  8. for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
  9. args[_key2] = arguments[_key2];
  10. }
  11.  
  12. var store = createStore.apply(undefined, args);// 调用createStore方法生成store
        // 初始化一个新的dispatch,暂时认为_dispatch = store.dispatch,从效果上看是这样的,暂时不明白为什么这样写,有待大牛指点。
  13. var _dispatch = function dispatch() {
  14. throw new Error('Dispatching while constructing your middleware is not allowed. ' + 'Other middleware would not be applied to this dispatch.');
  15. };
  16.  
  17. var middlewareAPI = {
  18. getState: store.getState,
  19. dispatch: function dispatch() {
  20. return _dispatch.apply(undefined, arguments);
  21. }
  22. };
        //让每一个中间件调用一次,参数为middlewareAPI,并把结果方法chain中,注意这个地方,是中间件的第一层,参数是{getState, dispatch}
  23. var chain = middlewares.map(function (middleware) {
  24. return middleware(middlewareAPI);
  25. });
        // 将各个中间件的功能组合到 dispatch 上,生成新的dispatch,注意此时是中间件的第二层, 参数是store.dispatch (关于 compose 解析)
  26. _dispatch = compose.apply(undefined, chain)(store.dispatch);
        return _extends({},
          store, // 最终返回的是store数据和加强后的dispatch
  27.       {dispatch: _dispatch}
  28. );
  29. };
  30. };
  31. }

  a、applyMiddleware 方法本身

    它首先通过一个for循环,将它的形参以数组元素的形式放到 middleware 中,并返回了一个形参为 createStore 方法(即为标注的func1);

  b、形参为 createStore 方法(即为标注的func1)

    这货很懒,只是返回了一个有很多参数的方法(即为标注的func2);

  c、很多参数的方法(即为标注的func2)

    这个方法和 applyMiddleware 一样,它首先通过一个for循环,将它的形参以数组元素的形式放到 args中;

  具体源码的解析,请看源码的注释;

中间件的编写

  我在源码的解析中,写了两个注意,分别是中间件的第一层和第二层,多以中间件的外面两层应该是如下的:

  1. const timeOutMiddleware = ({ dispatch, getState }) => {
  2. return (storeDispatch) => {
  3. return { ... };
  4. };
  5. }

  根据 compose 的操作原理,每一个中间件,即 chain 中的每一个元素,参数都是前一个中间件的组合后的 dispatch,返回的都是在参数的基础上组合自己功能后的dispatch,chain最后一个元素参数是store.dispatch。因此return的应该是一个通过这些中间件加强后的 dispatch。在此,我们就可以根据action传入的数据进行区分,加入我们中间件具体需要处理的情况。如下:

  1. const timeOutMiddleware = ({ dispatch, getState }) => (storeDispatch) => (action) => {
  2. if (typeof action === 'function') {
  3. return action(dispatch, getState);
  4. } else {
  5. return storeDispatch(action);
  6. }
  7. };

  如上,我们如果传入正常的action,我们就执行正常的store.dispatch。如果我们 action 传入的是 function 类型,那么这就是我们中间件处理的情况了。在action的function中我们可以拿到 store 的 dispatch 和 store 的 getState。当然我们在这个方法中可以异步的获取服务端的数据,然后根据成功或者失败的结果,通过 dispatch 再次分发一个正常的 action 同步我们获取到的数据,执行相应的操作。如下

  1. deleteStaff = (data) => {
  2. const { dispatch } = this.props;
  3. const { staffId } = data;
  4. const action = (dispatchd, getState) => {
  5. setTimeout(() => {
  6. dispatchd({type: 'DELETE', payload: {staffId}});
  7. }, 3000);
  8. };
  9. dispatch(action);
  10. };

这是一个方法,删除一条数据,通过 setTimeout 模仿异步,在3秒后,再次发一个 action,执行删除数据;

本文栗子的代码:https://github.com/wayaha/react-demos-middleware

(对您有帮助的话,请您帮我点颗 star)

redux 中间件 --- applyMiddleware 源码解析 + 中间件的实战的更多相关文章

  1. 阿里消息队列中间件 RocketMQ源码解析:Message发送&接收

  2. .Net Core 中间件之主机地址过滤(HostFiltering)源码解析

    一.介绍 主机地址过滤中间件相当于一个白名单,标记哪些主机地址能访问接口. 二.使用 新建WebAPI项目,修改Startup中的代码段如下所示.下面表示允许主机名为“localhost”的主机访问( ...

  3. TongWEB与JOnAS 对比,国产中间件战斗机东方通TongWEB源码解析

    转自网址: http://bbs.51cto.com/thread-489819-1-1.html 首先需要声明的是,本人出于技术爱好的角度,以下的文字只是对所看到的一些情况的罗列,偶尔附加个人的一些 ...

  4. AspNetCore源码解析_1_CORS中间件

    概述 什么是跨域 在前后端分离开发方式中,跨域是我们经常会遇到的问题.所谓的跨域,就是处于安全考虑,A域名向B域名发出Ajax请求,浏览器会拒绝,抛出类似下图的错误. JSONP JSONP不是标准跨 ...

  5. AspNetCore3.1源码解析_2_Hsts中间件

    title: "AspNetCore3.1源码解析_2_Hsts中间件" date: 2020-03-16T12:40:46+08:00 draft: false --- 概述 在 ...

  6. redux的源码解析

    一. redux出现的动机 1. Javascript 需要管理比任何时候都要多的state2. state 在什么时候,由于什么原因,如何变化已然不受控制.3. 来自前端开发领域的新需求4. 我们总 ...

  7. Redux系列x:源码解析

    写在前面 redux的源码很简洁,除了applyMiddleware比较绕难以理解外,大部分还是 这里假设读者对redux有一定了解,就不科普redux的概念和API啥的啦,这部分建议直接看官方文档. ...

  8. Redux异步解决方案之Redux-Thunk原理及源码解析

    前段时间,我们写了一篇Redux源码分析的文章,也分析了跟React连接的库React-Redux的源码实现.但是在Redux的生态中还有一个很重要的部分没有涉及到,那就是Redux的异步解决方案.本 ...

  9. redux:applyMiddleware源码解读

    前言: 笔者之前也有一篇关于applyMiddleware的总结.是applyMiddleware的浅析. 现在阅读了一下redux的源码.下面说说我的理解. 概要源码: step 1:  apply ...

随机推荐

  1. (十八)TableView实践(多组汽车品牌展示)

    对于多组数据,可能会用到模型的嵌套. 例如多组汽车,每组是一个模型,组内有多辆车的信息,每辆车的信息也是一个模型,相当于模型中有模型. 可以看到,每个item是一个字典,这要创建一个模型,而模型内部的 ...

  2. 《java入门第一季》之面向对象(重头戏多态)

    接下来介绍java第三大特性--多态性 /* 多态:同一个对象(事物),在不同时刻体现出来的不同状态. 举例: 猫是猫,猫是动物. 水(液体,固体,气态). 多态的前提: A:要有继承关系. B:要有 ...

  3. Leetcode_62_Unique Paths

    本文是在学习中的总结,欢迎转载但请注明出处:http://blog.csdn.net/pistolove/article/details/43404205 A robot is located at ...

  4. OpenCV 实现颜色直方图

    颜色直方图是在许多图像检索系统中被广泛采用的颜色特征.它所描述的是不同色彩在整幅图像中所占的比例,而并不关心每种色彩所处的空间位置,即无法描述图像中的对象或物体.颜色直方图特别适于描述那些难以进行自动 ...

  5. 【翻译】在Ext JS集成第三方库

    原文地址:http://www.sencha.com/blog/integrating-ext-js-with-3rd-party-libraries/ 作者:Kevin Kazmierczak Ke ...

  6. saiku显示不出新的cube(加载的cube,saiku会保存到缓存中,不重新加载)

    当用workbench 修改cube后,保存到saiku路径. saiku读取该cube时,如果以前加载过该cube(同路径,同名).则不会新加载,而是用缓存中的cube,这个cube是以前的cube ...

  7. REST(Representational State Transfer表述性状态转移)

    参考内容:http://www.csdn.net/article/2013-06-13/2815744-RESTful-API 定义了一组体系架构原则,您可以根据这些原则设计以系统资源为中心的 Web ...

  8. SMO实现

    #include "stdio.h" #include <vector> using namespace std; float function(float alfa[ ...

  9. OpenCV由汉字生成图片(透明)----可以对抗论文查重!!!

    今天听说很多同志们写毕业论文重复率过高的问题,大牛说用图片代替字就行了,我就想用OpenCV实现一下看看能不能搞,果不其然还是可以的!!!主要的难点在于普通格式的图片背景不透明,需要使用背景透明的pn ...

  10. 一个简单的基于 DirectShow 的播放器 1(封装类)

    DirectShow最主要的功能就是播放视频,在这里介绍一个简单的基于DirectShow的播放器的例子,是用MFC做的,今后有机会可以基于该播放器开发更复杂的播放器软件. 注:该例子取自于<D ...