你为什么需要异步操作? https://stackoverflow.com/questions/34570758/why-do-we-need-middleware-for-async-flow-in-redux  

  在redux基础篇的介绍中,我们介绍了redux的基本概念, 对于state的改变有了详尽的了解,但是并没有提到异步问题如何解决? 何为异步? Action 发出以后,Reducer 立即算出 State,这叫做同步;Action 发出以后,过一段时间再执行 Reducer,这就是异步

  在vue中对异步的实现是在actions下使用,如下所示:

 getDefaultAddress ({commit, state}) {
return new Promise(function (resolve, reject) {
axios.get('/bbg/user/get_default_address', {
params: {
uid: localStorage.getItem("uid")
}
}).then(function (response) {
if (response.data.code == ) {
console.log("获取默认地址成功");
// 存储默认地址
commit(UPDATE_DEFAULT_ADDRESS, response.data.data);
}
resolve();
});
});
},

  这里是一个异步的操作,即首先执行getDefaultAddress, 然后在执行这个的过程中,我们需要等到返回结果之后再去改变state数据,而vue的方法就是在判断成功的使用commit一个reducer,这样,就可以完成异步的操作了。

  那么react中是如何实现这种异步操作呢?  这时就需要使用工具: 中间件了。

  

一、中间件的概念

  为了理解中间件,让我们站在框架作者的角度思考问题:如果要添加功能,你会在哪个环节添加?

()Reducer:纯函数,只承担计算 State 的功能,不合适承担其他功能,也承担不了,因为理论上,纯函数不能进行读写操作。
()View:与 State 一一对应,可以看作 State 的视觉层,也不合适承担其他功能。
()Action:存放数据的对象,即消息的载体,只能被别人操作,自己不能进行任何操作。

  想来想去,只有发送 Action 的这个步骤,即store.dispatch()方法,可以添加功能。举例来说,要添加日志功能,把 Action 和 State 打印出来,可以对store.dispatch进行如下改造。

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

  

  上面代码中,store.dispatch进行了重定义在发送 Action 前后添加了打印功能。这就是中间件的雏形

  中间件就是一个函数,对store.dispatch方法进行了改造,在发出 Action 和执行 Reducer 这两步之间,添加了其他功能。

个人理解:

将具体业务和底层逻辑解耦的组件。

大致的效果是:
需要利用服务的人(前端写业务的),不需要知道底层逻辑(提供服务的)的具体实现,只要拿着中间件结果来用就好了。

举个例子:
我开了一家炸鸡店(业务端),然而周边有太多屠鸡场(底层),为了成本我肯定想一个个比价,再综合质量挑选一家屠鸡场合作(适配不同底层逻辑)。由于市场变化,合作一段时间后,或许性价比最高的屠鸡场就不是我最开始选的了,我又要重新和另一家屠鸡场合作,进货方式、交易方式等等全都要重来一套(重新适配)。

然而我只想好好做炸鸡,有性价比高的肉送来就行。于是我找到了一个专门整合屠鸡场资源的第三方代理(中间件),跟他谈好价格和质量后(统一接口),从今天开始,我就只需要给代理钱,然后拿肉就行。代理负责保证肉的质量,至于如何根据实际性价比,选择不同的屠鸡场,那就是代理做的事了。

  即中间件实际上就是在某两个步骤之间承担一部分任务,完成某个功能,这就是中间件。

  

二、 中间件的用法

  本教程不涉及如何编写中间件,因为常用的中间件都有现成的,只要引用别人写好的模块即可。比如,上一节的日志中间件,就有现成的redux-logger模块。这里只介绍怎么使用中间件

  

import { applyMiddleware, createStore } from 'redux';
import createLogger from 'redux-logger';
const logger = createLogger(); const store = createStore(
reducer,
applyMiddleware(logger)
);

  

  即先从redux中import使用中间件的插件,然后就可以在创建store的时候使用中间件了。 当然,中间件也是需要提前引入的。

  上面代码中,redux-logger提供一个生成器createLogger,可以生成日志中间件logger。然后,将它放在applyMiddleware方法之中,传入createStore方法,就完成了store.dispatch()的功能增强。

  补充:我们怎么知道 redux 模块是否含有 applyMiddleware 和 createStore模块呢?  我们可以在 npm install redux --save 之后在node-modules中找到redux,然后在redux中找到入口文件,接着进一步找到内层文件,找到 export , 我们在es/utils/index.js中可以看到导出文件如下:

  export { createStore, combineReducers, bindActionCreators, applyMiddleware, compose };

  这样,引入applyMiddleware中间件就没有任何问题了。

  需要注意的是:(1)createStore方法可以接受整个应用的初始状态作为参数,那样的话,applyMiddleware就是第三个参数了。

const store = createStore(
reducer,
initial_state,
applyMiddleware(logger)
);

  (2)中间件的次序有讲究。

const store = createStore(
reducer,
applyMiddleware(thunk, promise, logger)
);

上面代码中,applyMiddleware方法的三个参数,就是三个中间件。有的中间件有次序要求,使用前要查一下文档。比如,logger就一定要放在最后,否则输出结果会不正确

 

三、applyMiddlewares()

  上面我们使用了applyMiddlewares()方法,这个方法的作用就是使用中间件,之前,我们也已经找到其源码所在位置,现在粘贴如下所示:

  

export default function applyMiddleware() {
for (var _len = arguments.length, middlewares = Array(_len), _key = ; _key < _len; _key++) {
middlewares[_key] = arguments[_key];
} return function (createStore) {
return function (reducer, preloadedState, enhancer) {
var store = createStore(reducer, preloadedState, enhancer);
var _dispatch = store.dispatch;
var chain = []; var middlewareAPI = {
getState: store.getState,
dispatch: function dispatch(action) {
return _dispatch(action);
}
};
chain = middlewares.map(function (middleware) {
return middleware(middlewareAPI);
});
_dispatch = compose.apply(undefined, chain)(store.dispatch); return _extends({}, store, {
dispatch: _dispatch
});
};
};
}

  即这里可以接受任意多的中间件,然后将所有中间件放在一个middlewares数组中。  接着返回一个函数,使用中间件,在阮一峰老师的博客中也有此段源代码,写法有不同之处,只是这里是es5他的是es6的语法。

  

四、异步操作的基本思路

  理解了中间件以后,就可以处理异步操作了。

同步操作只要发出一种 Action 即可,异步操作的差别是它要发出三种 Action

操作发起时的 Action
操作成功时的 Action
操作失败时的 Action

  以向服务器取出数据为例,三种 Action 可以有两种不同的写法。

// 写法一:名称相同,参数不同
{ type: 'FETCH_POSTS' }
{ type: 'FETCH_POSTS', status: 'error', error: 'Oops' }
{ type: 'FETCH_POSTS', status: 'success', response: { ... } } // 写法二:名称不同
{ type: 'FETCH_POSTS_REQUEST' }
{ type: 'FETCH_POSTS_FAILURE', error: 'Oops' }
{ type: 'FETCH_POSTS_SUCCESS', response: { ... } }

  除了 Action 种类不同,异步操作的 State 也要进行改造,反映不同的操作状态。下面是 State 的一个例子。

let state = {
// ...
isFetching: true,
didInvalidate: true,
lastUpdated: 'xxxxxxx'
};

  

五、 redux-thunk 中间件

  这个中间件就可以解决异步actions的多次action触发问题。

六、 redux-promise中间件

  既然 Action Creator 可以返回函数,当然也可以返回其他值。另一种异步操作的解决方案,就是让 Action Creator 返回一个 Promise 对象。

  即此中间件解决的问题和redux-thunk中间件解决的问题相似。

redux进阶 --- 中间件和异步操作的更多相关文章

  1. Redux 入门教程(二):中间件与异步操作

    上一篇文章,介绍了 Redux 的基本做法:用户发出 Action,Reducer 函数算出新的 State,View 重新渲染. 但是,一个关键问题没有解决:异步操作怎么办?Action 发出以后, ...

  2. Redux 中间件和异步操作

    回顾一下Redux的数据流转,用户点击按钮发送了一个action,  reducer 就根据action 和以前的state 计算出了新的state, store.subscribe 方法的回调函数中 ...

  3. Redux的中间件原理分析

    redux的中间件对于使用过redux的各位都不会感到陌生,通过应用上我们需要的所有要应用在redux流程上的中间件,我们可以加强dispatch的功能.最近也有一些初学者同时和实习生在询问中间件有关 ...

  4. React:快速上手(7)——使用中间件实现异步操作

    React:快速上手(7)——使用中间件实现异步操作 本文参考链接:Stack Overflow redux-thunk 我们使用store.dispath进行派发时,只能传递一个普通对象进去,如下: ...

  5. Redux的中间件Middleware不难,我信了^_^

    Redux的action和reducer已经足够复杂了,现在还需要理解Redux的中间件.为什么Redux的存在有何意义?为什么Redux的中间件有这么多层的函数返回?Redux的中间件究竟是如何工作 ...

  6. (六)Redux进阶

    1 UI组件与容器组件的拆分 UI组件(傻瓜组件):只负责页面显示,没有任何逻辑 容器组件(聪明组件):并不去管UI到底长成什么样,关注的是整个业务逻辑 2 无状态组件 一个普通的函数就是无状态组件 ...

  7. 17. react redux的中间件

    1. redux 数据流程图 View 会派发一个 Action Action 通过 Dispatch 方法派发给 Store Store 接收到 Action 连同之前的 State 发给  Red ...

  8. Redux thunk中间件

    redux-thunk https://github.com/reduxjs/redux-thunk Why Do I Need This? Thunks are the recommended mi ...

  9. Redux进阶(像VUEX一样使用Redux)

    更好的阅度体验 前言 redux的问题 方案目标 如何实现 思考 前言 Redux是一个非常实用的状态管理库,对于大多数使用React库的开发者来说,Redux都是会接触到的.在使用Redux享受其带 ...

随机推荐

  1. PHP(四)表单的基本处理

  2. struct timeval 计时问题

    linux编程中,如果用到计时,可以用struct timeval获取系统时间.struct timeval的函数原型如下: struct timeval { __kernel_time_t tv_s ...

  3. RHEL7/CentOS7 Network Service开机无法启动的解决方法

    RHEL7/CentOS7安装完成并配置好所有网络相关配置后重启机器,使用systemctl --failed检查是否有失败的服务,发现在network服务启动失败,使用systemctl statu ...

  4. apache ap 并发测试工具

    可以使用 apache httpd 软件包里的 ab.exe 简单的做些网站的性能测试, ab.exe 是一个命令工具,所以不能双击运行, 在 cmd 下运行: ab.exe -n 1000 -c 5 ...

  5. 朋友,请待你的朋友——BUG好一点!

    程序猿嘛,难免会被BUG缠身,我相信,没有一个程序猿在被BUG缠身时是感觉轻松的,消灭BUG一定是你最大的愿望.本周,我们团队的项目进入调试阶段,各种BUG层出不穷,眼看下个周就要进行项目答辩会,所以 ...

  6. Algebraic Foundations ( Arithmetic and Algebra) CGAL 4.13 -User Manual

    理解: 本节主要介绍CGAL的代数结构和概念之间的互操作.与传统数论不同,CGAL的代数结构关注于实数轴的“可嵌入”特征.它没有将所有传统数的集合映射到自己的代数结构概念中,避免使用“数的类型”这一术 ...

  7. Mycat SqlServer Do not have slave connection to use, use master connection instead

    Do not have slave connection to use, use master connection instead 很奇怪啊 都是按照配置配置的 怎么就是不通呢 有点怀疑人生了吧 其 ...

  8. django系列8.2--django的中间件流程

    Django请求流程图 请求到达中间件之后,先按照正序执行每个注册中间件的process_reques方法,process_request方法返回的值是None,就依次执行,如果返回的值是HttpRe ...

  9. .Net开发工程师笔试试题

    第一部分[数据库技能] 附上自己做的答案,提出不足之处 现在有一个SQL Server 2000版本的数据库,里面包含有三个表Info.InfoReply.User,分别表示信息.信息评论和用户表,包 ...

  10. 【汉化】Acunetix Web Vulnerability Scanner 11.x汉化包

    破解补丁::http://www.52pojie.cn/thread-609275-1-1.html 汉化界面截图: 登陆界面 仪表盘 目标   漏洞 扫描 用户配置 汉化详情: 1.对UI界面大部分 ...