Thunk 引入背景
这是一个关于Redux异步数据流的故事。引入thunk中间件的完整故事在Redux官方中文文档异步数据流。一句话总结就是:原生Redux只支持同步数据流,所以需要引入中间件(middleware) Thnuk 来支持异步数据流。这里有两个关键字:中间件和异步。
Thunk 是什么
A thunk is a function that wraps an expression to delay its evaluation.
// calculation of 1 + 2 is immediate
// x === 3
let x = 1 + 2;
// calculation of 1 + 2 is delayed
// foo can be called later to perform the calculation
// foo is a thunk!
let foo = () => 1 + 2;
用Thunk传递的Action有什么特征
- An action creator that returns a function to perform asynchronous dispatch.
- An action creator that returns a function to perform conditional dispatch.
function incrementIfOdd() {
return (dispatch, getState) => {
const { counter } = getState();
if (counter % 2 === 0) {
return;
}
dispatch(increment());
};
}
Thunk 怎么用
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
const storeWithMiddleware = createStore(
rootReducer,
applyMiddleware(thunk)
);
function makeASandwichWithSecretSauce(forPerson) {
return function (dispatch) {
return fetchSecretSauce().then(
........
);
};
}
// Thunk middleware lets me dispatch thunk async actions
// as if they were actions!
storeWithMiddleware.dispatch(
makeASandwichWithSecretSauce('Me')
);
以上只是一个简单的总结,具体可以参考github上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就是一个嵌套函数。但又感觉啥也没看,还是不知道thunk是干啥的。。。。
我们先假设extraArgument为空,这样可以把问题简单化。
我在看这段源码时想了一下为啥感觉看了像没看一样,总结出了三个待回答的问题:
1. dispatch, getState 哪儿来的?
2. next干啥的?
3.为啥会有这种操作:action(dispatch, getState, extraArgument);
注:action作为一个用户自己根据业务逻辑自己编写的异步函数也不可能用redux中的dispatch和getState作参数呀。
dispatch, getState 哪儿来的?
next干啥的?
我在文章的开头用红色标注过,thunk的本质是中间件(middleware),所以要了解它必须放在Redux applyMiddleware这个大前提下,这样就迎刃而解了。
之前我写过一篇文章:理解Redux底层原理从applyMiddleware开始
首先,thunk是中间件,它的定义符合中间件函数的格式:
// 中间件大致定义格式
middlwware = store => next => action => {
.....
let result = next(action)
.....
return result;
}
下图是applyMiddleware的部分源码:
从图中我认为可以回答前两个问题,我就不多说了。
action(dispatch, getState, extraArgument)
首先,涉及到应用到thunk的action creator的合法写法:
let thunkActionCreator = () => (param1, param2) => {
....
param1({actionType: value});
.....
}
//注意:此时的dispatch其实已经包裹了引入的middleware的逻辑
//dispatch= fn1Middle(fn2Middle(store.dispatch))
storeWithMiddleware.dispatch(
thunkActionCreator()
);
从thunk的源码中可以看到,dispatch和getState方法分别赋给了param1 和param2(函数作用域链)。