理解redux-thunk

前言

前面我们已经用了三篇文章详细介绍了 Redux 的概念、原理及 Middleware 机制。今天我们来看一个 Redux 官方出品的 middleware 库:redux-thunk
可能大部分用了 Redux 的项目都会用到redux-thunk,但你有没有想过这个库到底是用来干嘛的?如果我不用它行不行?这篇文章我们就来详细聊一下这个库。
其实很早之前我就看过它的代码,看到它的代码量的时候被震惊了,没想到一个 GitHub 上 Star 数过万的项目,总的代码行数只有 10 行左右(我当时看的是 1.x 版本,代码量只有 8 行)。虽然我不喜欢用代码行数来衡量一个项目,但这么少的代码量当时还是觉得挺诧异的。

注意:这篇文章我会假定你对 redux 及 redux middleware 的工作机制有所了解,如果这部分还不是很熟悉,推荐你看一下前几篇文章

用法

首先,我们还是来看一下这个库的用法。redux-thunk是作为redux的 middleware 存在的,用法和普通 middleware 的用法是一样的,注册 middleware 的代码如下:

import thunkMiddleware from 'redux-thunk'
const store = createStore(reducer, applyMiddleware(thunkMiddleware))

注册后可以这样使用:

// 用于发起登录请求,并处理请求结果
// 接受参数用户名,并返回一个函数(参数为dispatch)
const login = (userName) => (dispatch) => {dispatch({ type: 'loginStart' })request.post('/api/login', { data: userName }, () => {dispatch({ type: 'loginSuccess', payload: userName })})
}
store.dispatch(login('Lucy'))

可以看到,redux-thunk主要的功能就是可以让我们dispatch一个函数,而不只是普通的 Object。后面我们会看到,这一点改变可以给我们巨大的灵活性。
了解了如何使用,接下来我们看一下它的实现原理。

什么是 thunk?

我记得我在很长的时间里都把redux-thunk的名字看成了redux-thank,理解成了感谢 redux。。。其实我觉得这个库最令人迷惑的地方之一就是它的名字。其实thunk是函数编程届的一个专有名词,主要用于calculation delay,也就是延迟计算。
用代码演示如下:

function wrapper(arg) {// 内部返回的函数就叫`thunk`return function thunk() {console.log('thunk running, arg: ', arg)}
}
// 我们通过调用wrapper来获得thunk
const thunk = wrapper('wrapper arg')// 然后在需要的地方再去执行thunk
thunk()

可以看到,这种代码的模式是非常简单的,以前我们可能都写过类似这样的代码,只是不知道这种代码叫做thunk而已。

redux-thunk 源码

由于redux-thunk的代码量非常少,我们直接把它的代码贴上来看一下。这里我们看的是最新版的v2.3.0的代码:

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 及它的 middleware 机制有所了解,那么上面这段代码是非常容易理解的。redux-thunk就是一个标准的 Redux middleware。
它的核心代码其实只有两行,就是判断每个经过它的action:如果是function类型,就调用这个function(并传入 dispatch 和 getState 及 extraArgument 为参数),而不是任由让它到达 reducer,因为 reducer 是个纯函数,Redux 规定到达 reducer 的 action 必须是一个 plain object 类型。
redux-thunk的原理就这么多,是不是非常简单?

起源

redux-thunk的代码和原理非常简单,但我觉得难的部分是为什么需要这样一个库。关于redux-thunk的起源可以看一下 Redux 001 号的 issue: How to dispatch many actions in one action creator[1]

大概意思就是问如何一次性发起多个 action,然后作者回答我可以让 actionCreator 返回一个函数。然后相关的 PR 如下: fix issue 001[2]

那个时候redux-thunk还没有独立,而是写在redux的 action 分发函数中的一个代码分支而已。和现在的redux-thunk逻辑一样,它会判断如果传入的 action 是一个function,就调用这个函数。现在将redux-thunk独立出去,用 middleware 的方式实现,会让 redux 的实现更加统一。
看到这里,其实我们对redux-thunk感到迷惑很大部分原因就是它涉及的thunk等的概念比较陌生而已,其实你大可以将它的名字理解为redux-function,也就是它只是让 dispatch 支持函数,仅此而已。

为什么需要?

现在我们理解了redux-thunk可以让我们 dispatch 一个 function,但是这有什么用呢?其实我觉得这是一项基础设施,虽然功能简单,但可扩展性极其强大。

比如很多时候我们需要在一个函数中写多次 dispatch。这也是上面 issue 中提到的问题。比如上面我们示例代码中,我们定义了 login 函数做 API 请求,在请求发出前我们可能需要展示一个全局的 loading bar,在请求结束后我们又需要将请求结果存储到 redux store 中。这都需要用到 redux 的 dispatch。

当然在一个函数中写多个 dispatch 只是我们可以做的事情之一,既然它是一个 function,而且并不要求像 reducer 一样是 pure function,那么我们可以在其中做任意的事情,也就是有副作用(side effect)的事情。

总结

redux-thunk是一个非常小的 library,但我觉得理解它的概念对于我们理解 redux 是至关重要的。它和另一个非常流行的库redux-saga一样,都是在 redux 中做side effect必不可少的。之后有时间我们会介绍一下redux-saga,如果感兴趣欢迎关注公众号。

最后附上前两篇关于 Redux 的文章,请参考:

深入理解 Redux Middleware
Redux 核心源码分析
理解 Redux

写文章不易,如果这篇文章帮助到了你,请帮忙关注和转发~ 谢谢

参考资料

[1]How to dispatch many actions in one action creator: https://github.com/reduxjs/redux/issues/1

[2]fix issue 001: https://github.com/reduxjs/redux/commit/c2a870a3a9a97ddc0f1c84fc40fe58b8f742a248

理解redux-thunk相关推荐

  1. 理解 Redux 的最好方式,是自己写一个

    react-redux 是 React 生态中比较(如果不是最的话)流行的一种状态管理方式,而它所依托的 redux,继承了 flux 的衣钵,并且引入了单一数据源.state 为只读.只能通过纯函数 ...

  2. 从源码理解Redux和Koa2的中间件机制

    Redux和Koa的中间件机制相关源码都很精简. 正文我将直接引用部分源码,并加以注释来帮助我们更清晰的理解中间件机制. Reudx redux的中间件机制在源码中主要涉及两个模块 内部的compos ...

  3. 学习 redux 源码整体架构,深入理解 redux 及其中间件原理

    如果觉得内容不错,可以设为星标置顶我的公众号 1. 前言 你好,我是若川.这是学习源码整体架构系列第八篇.整体架构这词语好像有点大,姑且就算是源码整体结构吧,主要就是学习是代码整体结构,不深究其他不是 ...

  4. 理解redux中Middleware

    如果你使用过 Express 或者 Koa 等服务端框架, 那么应该对 middleware 的概念不会陌生. 在这类框架中,middleware 是指可以被嵌入在框架接收请求到产生响应过程之中的代码 ...

  5. 通俗易懂的理解 Redux(知乎)

    1. React有props和state: props意味着父级分发下来的属性[父组件的state传递给子组件  子组件使用props获取],state意味着组件内部可以自行管理的状态,并且整个Rea ...

  6. 深入理解redux之从redux源码到react-redux的原理

    在使用react的过程中,用redux来管理应用中的状态,使应用流更清晰的同时也会有小小的疑惑,比如reducer在redux中时怎么发挥作用的,为什么只要写好reducer,和dispatch特定a ...

  7. 深入理解redux之reducer为什么是纯函数

    reducer是redux的三个核心概念之一,它指定了应用状态的变化如何响应 actions 并发送到 store,需要由开发人员自己定义,提起reducer,最常想到的一个准则是reducer要是纯 ...

  8. Redux 异步数据流-- thunk中间件源码解析

    Thunk 引入背景 这是一个关于Redux异步数据流的故事.引入thunk中间件的完整故事在Redux官方中文文档异步数据流.一句话总结就是:原生Redux只支持同步数据流,所以需要引入中间件(mi ...

  9. 【瞎写代码】系列之redux表面理解

    最近在翻boss,感觉今年前端的风向标的确是react,火爆程度完全超过了其他框架,所以为了跟上潮流,不得不开始使用react了,既然用了react就免不了要研究一下redux.关于redux的使用场 ...

  10. redux之compose的理解

    redux之compose的理解 redux之compose的理解 应用 reduce方法 compose函数 redux之compose的理解 应用 最近给自己的react项目添加redux的时候, ...

最新文章

  1. python asyncio理解_我实在不懂Python的Asyncio
  2. win7制作ntp服务器,如何将Win7作为NTP服务器
  3. Python攻克之路-xml模块
  4. 线性回归 最小二乘推导
  5. linux命令之route
  6. Word 2010—样式集
  7. nekohtml转换html时标签变大写的问题
  8. 统计调查制度申请流程和申请书公文模板
  9. android 动态库符号表,Android NDK隐藏jni动态库的内部符号表
  10. (实测可用)STM32CubeMX教程-STM32L431RCT6开发板研究串口通信(SPI flash)
  11. 【肥朝】从JDK中,我们能学到哪些设计模式?
  12. Oracle亿级数据查询处理(数据库分表、分区实战)
  13. Docker容器技术原理(三)rootfs
  14. iPhone历史上的创新,你都知道吗?
  15. 对数组中重复的值进行重命名
  16. 虚拟机远程工具MobaXterm(Network error: Connection timed out问题)以及虚拟机无IP地址和NetWork失效问题
  17. 中国电信校招笔试java_中国电信校园招聘笔试考什么?
  18. ORB 特征提取算法(理论篇)
  19. YOLOv5行人检测
  20. 网页制作课程设计(野生动物园)

热门文章

  1. 分布式系统设计模式,你用过哪些?
  2. 0422-团队项目开发
  3. MOSFET 和 IGBT 栅极驱动器电路的基本原理学习笔记(六)变压器耦合栅极驱动
  4. Dubbo从入门到实战
  5. node安装后的设置(node_global和node_cache) - windows
  6. dds:core:policy
  7. web网页引入自定义字体设置
  8. 反向传播 - 李宏毅机器学习笔记
  9. Python之Excel图片处理(将excel chart另存为图片)
  10. Status of node rabbit@xxxxx... Error: unable to perform an operation on node ‘rabbit@xxxx