前传  中间件的由来

  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 的源码

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

  a、applyMiddleware 方法本身

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

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

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

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

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

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

中间件的编写

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

const timeOutMiddleware = ({ dispatch, getState }) => {
return (storeDispatch) => {
return { ... };
};
}

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

const timeOutMiddleware  = ({ dispatch, getState }) => (storeDispatch) => (action) => {
if (typeof action === 'function') {
return action(dispatch, getState);
} else {
return storeDispatch(action);
}
};

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

deleteStaff = (data) => {
const { dispatch } = this.props;
const { staffId } = data;
const action = (dispatchd, getState) => {
setTimeout(() => {
dispatchd({type: 'DELETE', payload: {staffId}});
}, 3000);
};
dispatch(action);
};

这是一个方法,删除一条数据,通过 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. linux知识汇总

    1.     利用Ctrl+Alt+F1到Ctrl+Alt+F6在6个虚拟控制台之间切换,利用Ctrl+Alt+F7切换回图形界面. 2.     使用who命令来判断谁在系统上及其登录方式.id命令 ...

  2. Leetcode_75_Sort Colors

    本文是在学习中的总结,欢迎转载但请注明出处:http://blog.csdn.net/pistolove/article/details/43302343 Given an array with n  ...

  3. DBUtils源码分析

    其实,在这篇文章里,我只是分析了dbutis的query的运作流程. 至于类为什么要这样设计,蕴含的设计模式等等高级知识点咱们在下节再探讨. 先看看最简单的DBUtils是如何工作的. 数据库里有一张 ...

  4. Android开发技巧——实现可复用的ActionSheet菜单

    在上一篇<Android开发技巧--使用Dialog实现仿QQ的ActionSheet菜单>中,讲了这种菜单的实现过程,接下来将把它改成一个可复用的控件库. 本文原创,转载请注明出处: h ...

  5. 苹果新的编程语言 Swift 语言进阶(四)--字符串和收集类型

    一.字符串( String  )和字符类型(Character) 字符串是一种字符的带次序的收集类型(相当于数组),字符是字符串中的元素. 在Swift 语言中,字符串是编码独立的Unicode字符的 ...

  6. 基于SVMLight的文本分类

    支持向量机(Support Vector Machine)是Cortes和Vapnik于1995年首先提出的,它在解决小样本 .非线性及高维模式识别 中表现出许多特有的优势,并能够推广应用到函数拟合等 ...

  7. The content of elements must consist of well-formed character data or markup

    java 中使用dom4j解析含有特殊字符的xml文件出现了如题的错误 这个时候需要在特殊字符外面加上 <![CDATA[ /6169220648+20671/1>7+-47390045& ...

  8. Android Studio Gradle Configuration Errors总结

    初次看到这个错误,我从下手Error:Configuration with name 'default' not found.  只知道这是由于android的grad项目构建的时候出现的错误,但是具 ...

  9. Java工程师成神之路思维导图

    前面看Hollis的微信公众号更新了Java工程师成神之路的文档,感觉里面的内容清晰.齐全,可以用来审视自己,也能够知道自己在那些方面可以继续前行,想着有时间把它画下来,画下来之后分享出来. 主要内容 ...

  10. c# 获取TFS结构 文件

    #region 获取最新版本 /// <summary> /// 获取最新版本 /// </summary> /// <param name="server_u ...