redux-thunk 是一个比较流行的 redux 异步 action 中间件。redux-thunk 帮助你统一了异步和同步 action 的调用方式,把异步过程放在 action 级别解决,对 component 没有影响。下面通过例子一步步来看看。
异步方法的调用
store.dispatch({ type: 'SHOW_NOTIFICATION', text: 'You logged in.' })
setTimeout(() => {
store.dispatch({ type: 'HIDE_NOTIFICATION' })
}, 5000)
这是一个简单的例子,他做事情很简单,5s 后关闭提醒。
在一个被 redux connect 过的 component 中,是如下这个样子:
this.props.dispatch({ type: 'SHOW_NOTIFICATION', text: 'You logged in.' })
setTimeout(() => {
this.props.dispatch({ type: 'HIDE_NOTIFICATION' })
}, 5000)
本质上两者没有区别,只是被 connect 过的 component 中的 ****this.props**** 有了 ****dispatch**** 属性。
redux-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
的源码非常简洁,出去空格一共只有11行,这11行中如果不算上}
,则只有8行。最后三行模块的导出方法很好理解,
// thunk.withExtraArgument的结果如下
function createThunkMiddleware(extraArgument) {
return ({ dispatch, getState }) => next => action => {
if (typeof action === 'function') {
return action(dispatch, getState, extraArgument);
}
return next(action);
};
}
thunk.withExtraArgument
允许给返回的函数传入额外的参数,它比较难理解的部分和thunk
一样,如下:
({ dispatch, getState }) => next => action => {
if (typeof action === 'function') {
return action(dispatch, getState, extraArgument);
}
return next(action);
}
上述代码使用函数参数的解构加上连用三个箭头函数,显得非常简洁,单同时也带来了理解的困难(这也是箭头函数的缺点之一)。把上述代码在babel REPL中转译为ES5语法后,我们看到以下结果:
"use strict";
function createThunkMiddleware(extraArgument) {
return function (_ref) {
var dispatch = _ref.dispatch,
getState = _ref.getState;
return function (next) {
return function (action) {
if (typeof action === "function") {
return action(dispatch, getState, extraArgument);
}
return next();
};
};
};
}
这下,代码一下子我们能看懂了,不过稍等这里的dispatch
,getState
,next
还有action
又是什么?
我们先看看,在reudx
中我们如何使用中间件:
let store = createStore(
reducer,
applyMiddleware(thunk)
);
看来,要解开dispatch
,getState
,next
,action
从哪里来,我们还需要再看看applyMiddleware
的源码,如下:
export default function applyMiddleware(...middlewares) {
return (createStore) => (...args) => {
const store = createStore(...args)
let dispatch = store.dispatch
let chain = []
const middlewareAPI = {
getState: store.getState,
dispatch: (...args) => dispatch(...args)
}
chain = middlewares.map(middleware => middleware(middlewareAPI))
dispatch = compose(...chain)(store.dispatch)
return {
...store,
dispatch
}
}
}
可以看出其中middleware
执行时传入的参数对象middlewareAPI
中确实包含getState
和dispatch
两项,next
则来自dispatch = compose(...chain)(store.dispatch)
这一句中的store.dispatch
,而action
在dispatch
某个action
时传入。