最近在看redux,主要是redux官方教程(参考文章1)和网上文章(参考文章2),基础部分已经看完,正在理解middleware中间件部分,自我感觉中间件的思想不难理解,主要是它的实现方式涉及到函数式编程,真的太抽象了。redux-thunk是一种中间件,它能使你在action creator中返回函数,此返回函数就是thunk函数,模拟一下就是
代码语言:javascript复制// thunk函数
(dispatch,getState,extraCustomArgument) => {...}
它接收三个参数,dispatch用于触发action,getState用于获取state,extraCustomArgument用于自定义参数。同样此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,代码如下:
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就是一个扩展功能的中间件,它的源代码实现非常少!之后估计也要学习一下,到时再写一篇文章。
参考文章
- http://cn.redux.js.org/
- https://github.com/brickspert/blog/issues/22
- https://github.com/reduxjs/redux-thunk
- http://www.ruanyifeng.com/blog/2015/05/thunk.html