2020.04.02
redux-thunk 是一个 redux 的中间件,主要解决了异步调用 dispatch 的问题,也就是说,通过 redux-thunk 我们能实现异步 action。
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;
说来简单,thunk 的核心部分只有四行,
if (typeof action === 'function') {
return action(dispatch, getState, extraArgument);
}
return next(actions);
即,针对于 dispatch 接收的参数 action 进行类型判断:
dispatch 等为入参执行这个函数并返回结果;因为这样的处理,我们在编写 action creator 的时候就可以这样来写:
const increment = () => ({type: 'INCREMENT'});
const incrementAsync = () => (dispatch) => {
setTimeout(() => {
dispatch(increment());
}, 1000);
};
dispatch(increment()); // increase immediately
dispatch(incrementAsync()); // increase delay 1s
核心部分的理解还是相对较为容易的,但是最让我困惑的是作为入参的 dispatch,在读过 applyMiddleware 之后会知道有一个 middlewareAPI 的入参,这就是源码中解构入参的来源,可是明明其中定义的 dispatch 我记得是一个 throw new Error('...') 的函数,为什么这里作为触发 action 的方法会有效呢?
let dispatch = () => {console.log('constructing ...')}
const store = {
dispatch () {console.log('store.dispatch ...')}
}
const enhancer = {
dispatch () {console.log('enhancer.dispatch ...')}
}
const api = {
dispatch: (...args) => dispatch(...args)
}
api.dispatch(); // constructing ...
dispatch = store.dispatch;
api.dispatch(); // store.dispatch ...
dispatch = enhancer.dispatch;
api.dispatch(); // enhancer.dispatch ...
可以看到三次调用 api.dispatch() 打印结果都是不同的,这里有个概念就是 延迟执行,当调用 api.dispatch 的时候,实际上回去寻找第一行中定义的 dispatch 变量,三次调用 dispatch 指向不同的函数,所以打印不同结果。而实际上,延迟执行 的概念在 applyMiddleware 和 redux-thunk 中都有。