redux-thunk中间件

2022-10-28 13:36:02 浏览数 (3)

最近在看redux,主要是redux官方教程(参考文章1)和网上文章(参考文章2),基础部分已经看完,正在理解middleware中间件部分,自我感觉中间件的思想不难理解,主要是它的实现方式涉及到函数式编程,真的太抽象了。redux-thunk是一种中间件,它能使你在action creator中返回函数,此返回函数就是thunk函数,模拟一下就是

代码语言:javascript复制
// thunk函数
(dispatch,getState,extraCustomArgument) => {...}

它接收三个参数,dispatch用于触发actiongetState用于获取stateextraCustomArgument用于自定义参数。同样此thunk函数可以被dispatch,并且thunk函数的返回值也是dispatch的返回值,另外在action creator中也可以dispatch其他的thunk函数。redux-thunk的作用大致就是上面总结的,此文章也只是将官网readme给翻译一下(参考文章3)。

redux-thunk解决了什么问题


在基本的redux中,只能dispatch同步的action来更新state,那么对于dispatch异步的action来更新state呢?就要使用中间件了,而redux-thunk就是这样一个中间件。

具体的改变


  • 之前action creator返回的是action对象,现在可以返回一个thunk函数,这个函数可以执行一些副作用,不再需要保持它的纯净。它可以异步或者在某一条件满足时dispatch action,代码如下:
代码语言:javascript复制
const INCREMENT_COUNTER = 'INCREMENT_COUNTER'
// 普通的action creator
function increment() {
  return {
      type: INCREMENT_COUNTER
    }
}
// 返回thunk函数的action creator,这个是延迟(异步)执行
function incrementAsync() {
  // 可以看出其中使用了 setTimeout,即执行了副作用
  return (dispatch) => {
    setTimeout(() => {dispatch(increment())},1000)
  }
}
// 返回thunk函数的action creator,这个是满足一定条件执行
function incrementIfOdd() {
  return (dispatch,getState) => {
    const {counter} = getState()
    if (counter % 2 === 0) {
      // 终止,什么也不做
      return
    }
    dispatch(increment())
  }
}

thunk是什么


thunk是一个函数,它封装一个表达式,使得表达式可以延时计算。

代码语言:javascript复制
// thunk函数
function thunk() {
  return 1 2
}
// 当你call时,才能得到 1 2 的值
thunk() // 3

此函数其实早就有了,之前是用于“传名调用”的一种实现策略,用来替换某个表达式。

代码语言:javascript复制
// 对于函数参数的求值,有两种方式:
// 1. 传值调用:即在参数传入函数体之前,就进行求值,
//    这种方式可能在函数体不需要此参数时,造成浪费
// 2. 传名调用:即在函数体内用到时,才进行求值,可以体会一下下面的例子
// 传名调用
function f(x) {
  return x*2
}
f(3 2)
// 等同于
// thunk函数
function thunk() {
  return 3 2
}
function f(thunk) {
  return thunk()*2
}

对于JavaScript来说,thunk具有另一种含义,用于将多参数函数转换成单参数函数,且只接受callback作为参数。

代码语言:javascript复制
// 正常版本的readFile函数
fs.readFile(fileName,callback)
// 经过thunk改变后
const thunkReadFile = thunk(fileName)
const result = thunkReadFile(callback)
// thunk的过程
const thunk = (fileName) => (callback) => fs.readFile(fileName,callback)

那么对于有callback的函数来说,都可以进行thunk化,写一个thunk函数转换器。

代码语言:javascript复制
// thunk函数转换器
const thunkTrans = (fn) = > () => {
  // 将arguments类数组转换为数组,其实不一定要转换,使用(...)也可
  const args = Array.prototype.slice.call(arguments)
  return (callback) => {
    args.push(callback)
    return fn.apply(this,args)
  }
}
// 有时候真的感叹js的函数真是太神奇了,不,是js执行机制太神奇了!
// 使用的时候比上面多一步
const createThunkReadFile = thunkTrans(fs.readFile)
const thunkReadFile = createThunkReadFile(fileName)
const result = thunkReadFile(callback)

以上都是参考阮一峰老师的文章(参考文章4)。

复杂用法


就是说在action creator中还可以dispatch其他的action creator,不论是返回action对象还是返回一个函数。这对于操作异步流来说真是太方便了,想一想.then().then(). . .

另一个就是传入extraCustomArgument参数。这一部分请直接参考redux-thunk官方文档。

可以看出,redux-thunk就是一个扩展功能的中间件,它的源代码实现非常少!之后估计也要学习一下,到时再写一篇文章。

参考文章

  1. http://cn.redux.js.org/
  2. https://github.com/brickspert/blog/issues/22
  3. https://github.com/reduxjs/redux-thunk
  4. http://www.ruanyifeng.com/blog/2015/05/thunk.html

0 人点赞