分享

《React

 飞鹰飞龙飞天 2016-11-14
 我们再前面讲的 redux 中的数据流都是同步的,流程如下:
[javascript] view plain copy
在CODE上查看代码片派生到我的代码片
  1. view -> actionCreator -> action -> reducer -> newState -> container component   

但是,在大多数的前端业务场景中,需要和后端产生异步交互,譬如:网络api的请求。


Redux中怎么来实现异步的数据流呢?


异步Action

通常我们创建的Action如下:

[javascript] view plain copy
在CODE上查看代码片派生到我的代码片
  1. export const REQUEST_POSTS = 'REQUEST_POSTS'  
  2. export function requestPosts(subreddit) {  
  3.   return {  
  4.     type: REQUEST_POSTS,  
  5.     subreddit  
  6.   }  
  7. }  

我们来创建一个异步的Action:

[javascript] view plain copy
在CODE上查看代码片派生到我的代码片
  1. export function fetchPosts(subreddit) {  
  2.   
  3.   return function (dispatch) {  
  4.   
  5.     dispatch(requestPosts(subreddit))  
  6.   
  7.     return fetch(`http:///xxx`)  
  8.       .then(response => response.json())  
  9.       .then(json =>  
  10.         // 可以多次 dispatch!  
  11.         dispatch(receivePosts(subreddit, json))  
  12.       ).catch(error){  
  13.           
  14.       }  
  15.   }  
  16. }  
在异步Action中,我们diapatch了一个requestPosts 的Action,同时根据fetch的结果,dispatch了不同的Action。

实际上,异步Action返回的是一个function。


当 action creator 返回函数时,这个函数会被 Redux Thunk middleware 执行。

这个函数并不需要保持纯净;它还可以带有副作用,包括执行异步 API 请求。这个函数还可以 dispatch action,就像 dispatch 前面定义的同步 action 一样。


Middleware

Middleware提供的是位于 action 被发起之后,到达 reducer 之前的扩展点。 你可以利用 Redux middleware 来进行日志记录、创建崩溃报告、调用异步接口或者路由等等。

一个 middleware 的结构 ,其核心的部分为

[javascript] view plain copy
在CODE上查看代码片派生到我的代码片
  1. function(action) {  
  2.     // 调用后面的 middleware  
  3.     next(action)  
  4. }  
middleware 完全掌控了 reducer 的触发时机, 也就是 action 到了这里完全由中间件控制,不乐意就不给其他中间件处理的机会,而且还可以控制调用其他中间件的时机。

给个例子:

[javascript] view plain copy
在CODE上查看代码片派生到我的代码片
  1. const logger = store => next => action => {  
  2.     if(typeof action === 'function') console.log('dispatching a function');  
  3.     else console.log('dispatching', action);  
  4.     let result = next(action);  
  5.     console.log('next state', store.getState());  
  6.     return result;  
  7. }  


其实目前已经有很多第三方 redux 组件支持异步 action,其中如:


redux-thunk

redux-thunk 是 redux 官方文档中用到的异步组件,实质就是一个 redux 中间件,thunk 听起来是一个很陌生的词语,先来认识一下什么叫 thunk

A thunk is a function that wraps an expression to delay its evaluation.
简单来说一个 thunk 就是一个封装表达式的函数,封装的目的是延迟执行表达式

[javascript] view plain copy
在CODE上查看代码片派生到我的代码片
  1. // 1 + 2 立即被计算 = 3  
  2. let x = 1 + 2;  
  3.   
  4. // 1 + 2 被封装在了 foo 函数内  
  5. // foo 可以被延迟执行  
  6. // foo 就是一个 thunk   
  7. let foo = () => 1 + 2;  

redux-thunk 是一个通用的解决方案,其核心思想是让 action 可以变为一个 thunk ,这样的话:

同步情况:dispatch(action)
异步情况:dispatch(thunk)

我们已经知道了 thunk 本质上就是一个函数,函数的参数为 dispatch。


我们来看一下redux-thunk的源码:

[javascript] view plain copy
在CODE上查看代码片派生到我的代码片
  1. function createThunkMiddleware(extraArgument) {  
  2.   return function (_ref) {  
  3.     var dispatch = _ref.dispatch;  
  4.     var getState = _ref.getState;  
  5.     return function (next) {  
  6.       return function (action) {  
  7.         if (typeof action === 'function') {  
  8.           return action(dispatch, getState, extraArgument);  
  9.         }  
  10.   
  11.         return next(action);  
  12.       };  
  13.     };  
  14.   };  
  15. }  
  16.   
  17. var thunk = createThunkMiddleware();  
  18. thunk.withExtraArgument = createThunkMiddleware;  
  19.   
  20. exports['default'] = thunk;  

实现的逻辑如下:

如果 action 也就是一个 thunk,执行 action 相当于执行了异步逻辑action(dispatch, getState, ...)
        action 中执行 dispatch,开始新的 redux 数据流,重新回到最开始的逻辑(thunk 可以嵌套的原因)
        把执行的结果作为返回值直接返回,直接返回并没有调用其他中间件,也就意味着中间件的执行在这里停止了

如果不是函数直接调用其他中间件并返回。


参考:https://zhuanlan.zhihu.com/p/21398212

           http://cn.redux./docs/advanced/AsyncActions.html


    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多