浅析redux-thunk中间件源码

大多redux的初学者都会使用redux-thunk中间件来处理异步请求,其理解简单使用方便(具体使用可参考官方文档)。我自己其实也一直在用,最近偶然发现其源码只有一个函数,考虑到其在Github上至今有6747个赞,因此比较好奇它究竟给出了一个怎么样的函数。

什么是thunk?

在看具体的源码之前,我们先看一个词thunk,理解这个词有助于我们理解源码。

A thunk is a function that wraps an expression to delay its evaluation. 维基百科中是这样解释thunk的:thunk是一种包裹一些稍后执行的表达式的函数。

redux-thunk源码

function createThunkMiddleware(extraArgument) {
return ({ dispatch, getState }) => next => action => {
if (typeof action === 'function') {
return action(dispatch, getState, extraArgument);
}
return next(action);
};
} const thunk = createThunkMiddleware();
thunk.withExtraArgument = createThunkMiddleware; export default thunk;

redux-thunk的源码非常简洁,出去空格一共只有11行,这11行中如果不算上},则只有8行。最后三行模块的导出方法很好理解,

// thunk的内容如下
({ dispatch, getState }) => next => action => {
if (typeof action === 'function') {
return action(dispatch, getState, extraArgument);
}
return next(action);
} // thunk.withExtraArgument的结果如下
function createThunkMiddleware(extraArgument) {
return ({ dispatch, getState }) => next => action => {
if (typeof action === 'function') {
return action(dispatch, getState, extraArgument);
}
return next(action);
};
}

thunk.withExtraArgument允许给返回的函数传入额外的参数,它比较难理解的部分和thunk一样,如下:

({ dispatch, getState }) => next => action => {
if (typeof action === 'function') {
return action(dispatch, getState, extraArgument);
}
return next(action);
}

上述代码使用函数参数的解构加上连用三个箭头函数,显得非常简洁,单同时也带来了理解的困难(这也是箭头函数的缺点之一)。把上述代码在babel REPL中转译为ES5语法后,我们看到以下结果:

"use strict";

function createThunkMiddleware(extraArgument) {
return function (_ref) {
var dispatch = _ref.dispatch,
getState = _ref.getState;
return function (next) {
return function (action) {
if (typeof action === "function") {
return action(dispatch, getState, extraArgument);
}
return next();
};
};
};
}

这下,代码一下子我们能看懂了,不过稍等这里的dispatch,getStatenext还有action又是什么?

我们先看看,在reudx中我们如何使用中间件:

let store = createStore(
reducer,
applyMiddleware(thunk)
);

看来,要解开dispatch,getState,next,action从哪里来,我们还需要再看看applyMiddleware的源码,如下:

export default function applyMiddleware(...middlewares) {
return (createStore) => (...args) => {
const store = createStore(...args)
let dispatch = store.dispatch
let chain = [] const middlewareAPI = {
getState: store.getState,
dispatch: (...args) => dispatch(...args)
}
chain = middlewares.map(middleware => middleware(middlewareAPI))
dispatch = compose(...chain)(store.dispatch) return {
...store,
dispatch
}
}
}

可以看出其中middleware执行时传入的参数对象middlewareAPI中确实包含getStatedispatch两项,next则来自dispatch = compose(...chain)(store.dispatch)这一句中的store.dispatch,而actiondispatch某个action时传入。

一般来说一个有效携带数据的action是如下这样的:

{
type: ADD_TODO,
text: 'Build my first Redux app'
}

加入redux-thunk后,action可以是函数了,依据redux-thunk的源码,我们可以看出如果传入的action是函数,则返回这个函数的调用,如果本身传入的函数是一个异步函数,我们完全可以在函数调用结束后,获取必要的数据再次触发dispatch由此实现异步效果。

小结

redux-thunk的源码总的来说还是很简单的,理解这个函数本身并不难,但是在彻底弄懂每一项却需要对reudx的部分源码有所了解。react官方文档中的Middleware一节讲解的非常好,也确实帮我理解了中间件的工作原理,非常推荐阅读。之前一直使用redux-thunk做异步处理,这段时间尝试了一下redux-saga,它非常优雅,可用于处理更加复杂的异步action,之后有时间会再总结一下它的用法,如果可以,也愿意再分析下它的源码,欢迎关注。

redux-thunk中间件源码的更多相关文章

  1. laravel中间件源码分析

    laravel中间件源码分析 在laravel5.2中,HTTP 中间件为过滤访问你的应用的 HTTP 请求提供了一个方便的机制.在处理逻辑之前,会通过中间件,且只有通过了中间件才会继续执行逻辑代码. ...

  2. Django-session中间件源码简单分析

    Django-session中间件源码简单分析 settings里有关中间件的配置 MIDDLEWARE = [ 'django.middleware.security.SecurityMiddlew ...

  3. 21.django中间件源码阅读

    回顾: 关于里面的源码流程大家可以全看视频,因为代码的跳动性很大,而且会多次调用通过一方法,所以关于中间源码的部分去找个视频看一看,我写的不是很清楚. # 1 cookie session # 2 f ...

  4. Redux thunk中间件

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

  5. 重新整理 .net core 实践篇——— 权限中间件源码阅读[四十六]

    前言 前面介绍了认证中间件,下面看一下授权中间件. 正文 app.UseAuthorization(); 授权中间件是这个,前面我们提及到认证中间件并不会让整个中间件停止. 认证中间件就两个作用,我们 ...

  6. Python 实现接口类的两种方式+邮件提醒+动态导入模块+反射(参考Django中间件源码)

    实现接口类的两种方式 方式一 from abc import ABCMeta from abc import abstractmethod class BaseMessage(metaclass=AB ...

  7. Python 实现抽象类的两种方式+邮件提醒+动态导入模块+反射(参考Django中间件源码)

    实现抽象类的两种方式 方式一 from abc import ABCMeta from abc import abstractmethod class BaseMessage(metaclass=AB ...

  8. 基于django中settings中间件源码思想,实现功能的插拔式设计

    这里我们用到一个非常重要的模块,importlib,利用它可以实现字符串转python代码,再利用反射进行操作,这样就可以实现插拔式设计. 一.我们先做个初级的,把所有文件放到初级思想文件夹下: 1. ...

  9. redux设计到源码 --- 美团点评技术团队(转)

    https://tech.meituan.com/redux-design-code.html

随机推荐

  1. Java压缩多个文件并导出

    controller层: /** * 打包压缩下载文件 */ @RequestMapping(value = "/downLoadZipFile") public void dow ...

  2. java, android的aes等加密库

    https://github.com/scottyab/AESCrypt-Android https://github.com/PDDStudio/EncryptedPreferences       ...

  3. Ajax保留浏览器历史的两种解决方案(Hash&Pjax)

    总是在github down点东西,github整个界面做的不错,体验也很好~对于其中的源代码滑动的特效最为喜欢了~刚开始以为这个只是普通的ajax请求效果,但是发现这个特效能够导致浏览器地址栏跟随变 ...

  4. python selenium webdriver方法封装(find_element_by)

    下面是对find_element_by_就行了封装,封装之后的高级方法就是getElement() 下面是具体的代码: def getElement(self, selector): "&q ...

  5. SQL语句中case函数

    case函数,严格的意义上来讲case函数已经试流程控制语句了,不是简单意义上的函数,不过为了方便,很多人将case函数称为流程控制函数. case函数的一般有两种用法:1.case expressi ...

  6. win7 +v Ubuntu 16.04 grub rescue 模式下修复 grub

    前几天整理了下电脑的分区,合并并删除一些分区,结果导致 grub 被破坏了,Ubuntu进不去了,启动后直接进入了 rescure 模式.后来又折腾了下,终于修复好了,现总结一下. 先说一下我的系统环 ...

  7. 《Python网络编程基础》第四章 域名系统

    域名系统(DNS) 是一个分布式的数据库,它主要用来把主机名转换成IP地址.DNS以及相关系统之所以存在,主要有以下两个原因:   它们可以使人们比较容易地记住名字,如www.baidu.com. 它 ...

  8. MySQL的GTID复制

    从mysql5.6开始引入全局事务标识符(GTID),即每个事务都有一个唯一的标识符.服务器上的每个事务都被分配一个唯一的事务标识符,这是一个64位非零的数值,根据事务提交的顺序分配.GTID的构成是 ...

  9. Linux学习笔记之Linux计划任务Crontab

    0x00 cron 简介 cron 是 UNIX, SOLARIS,LINUX 下的一个十分有用的工具.通过 cron 脚本能使计划任务定期地在系统后台自动运行. 0x01 cron 命令 cront ...

  10. Ubuntu下的MongoDB GUI 可视化管理工具

    目录 1 Robo 3T 2 NoSQLBooster for MongoDB(收费) 3 JetBrains Plugin Repository :: Mongo Plugin Ubuntu下的Mo ...