redux-thunk 是一個比較流行的 redux 異步 action 中間件。redux-thunk 幫助你統(tǒng)一了異步和同步 action 的調(diào)用方式,把異步過程放在 action 級別解決,對 component 沒有影響。下面通過例子一步步來看看。
異步方法的調(diào)用
store.dispatch({ type: 'SHOW_NOTIFICATION', text: 'You logged in.' })
setTimeout(() => {
store.dispatch({ type: 'HIDE_NOTIFICATION' })
}, 5000)
這是一個簡單的例子,他做事情很簡單,5s 后關(guān)閉提醒。
在一個被 redux connect 過的 component 中,是如下這個樣子:
this.props.dispatch({ type: 'SHOW_NOTIFICATION', text: 'You logged in.' })
setTimeout(() => {
this.props.dispatch({ type: 'HIDE_NOTIFICATION' })
}, 5000)
本質(zhì)上兩者沒有區(qū)別,只是被 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行。最后三行模塊的導(dǎo)出方法很好理解,
// thunk.withExtraArgument的結(jié)果如下
function createThunkMiddleware(extraArgument) {
return ({ dispatch, getState }) => next => action => {
if (typeof action === 'function') {
return action(dispatch, getState, extraArgument);
}
return next(action);
};
}
thunk.withExtraArgument允許給返回的函數(shù)傳入額外的參數(shù),它比較難理解的部分和thunk一樣,如下:
({ dispatch, getState }) => next => action => {
if (typeof action === 'function') {
return action(dispatch, getState, extraArgument);
}
return next(action);
}
上述代碼使用函數(shù)參數(shù)的解構(gòu)加上連用三個箭頭函數(shù),顯得非常簡潔,單同時也帶來了理解的困難(這也是箭頭函數(shù)的缺點之一)。把上述代碼在babel REPL中轉(zhuǎn)譯為ES5語法后,我們看到以下結(jié)果:
"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中我們?nèi)绾问褂弥虚g件:
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執(zhí)行時傳入的參數(shù)對象middlewareAPI中確實包含getState和dispatch兩項,next則來自dispatch = compose(...chain)(store.dispatch)這一句中的store.dispatch,而action在dispatch某個action時傳入。