深度剖析github上15.1k Star項(xiàng)目:redux-thunk

日益忙碌的一周又過(guò)去了,是時(shí)候開(kāi)始每周一次的總結(jié)復(fù)盤了,今天筆者就來(lái)剖析一下github中star數(shù)15.1k的開(kāi)源項(xiàng)目redux-thunk。
作為一名React方向的前端工程師,不管是被面試還是面試別人,大部分都會(huì)說(shuō)起redux-thunk的實(shí)現(xiàn)原理,因?yàn)樗浅=?jīng)典且有用,而且代碼量少的感人,只有短短12行代碼,卻能解決React開(kāi)發(fā)中同一個(gè)函數(shù)支持多dispatch和異步action的問(wèn)題(雖然這完全依賴于redux的中間件機(jī)制(Middleware))。
接下來(lái)筆者將從:
Redux的工作機(jī)制
中間件實(shí)現(xiàn)原理
redux-thunk源碼實(shí)現(xiàn)
這三個(gè)方面來(lái)帶大家徹底掌握redux-thunk源碼,從而對(duì)redux有更深入的了解和應(yīng)用。如果大家對(duì)react-redux-redux-thunk實(shí)戰(zhàn)感興趣的,讀完之后可以移步筆者的《徹底掌握redux》之開(kāi)發(fā)一個(gè)任務(wù)管理平臺(tái)
正文

redux解決的真正問(wèn)題是React組件間的狀態(tài)共享和狀態(tài)管理問(wèn)題,通過(guò)以上的6個(gè)核心api我們便能管理復(fù)雜的狀態(tài),并能監(jiān)聽(tīng)和追溯狀態(tài)的改動(dòng)。機(jī)制筆者總結(jié)如下:

redux工作機(jī)理基本了解之后,我們先看看一個(gè)實(shí)際的例子:
import actionType from './actionType'
class Actions {
static start() {
return {
type: actionType.CREATE_TODO_DOING
}
}
static ok(data, cb) {
cb && 'function' === typeof cb && cb(data);
return {
type: actionType.CREATE_TODO_SUCCESS,
payload: data
}
}
static fail(data, cb) {
cb && 'function' === typeof cb && cb(data);
return {
type: actionType.CREATE_TODO_FAILURE,
payload: data
}
}
}
到這一步我們?nèi)匀徊荒苤苯舆M(jìn)入redux-thunk的源碼分析,因?yàn)槲覀冞€是不清楚如何解決上述步驟,因?yàn)槲覀冞€沒(méi)有了解redux的中間件機(jī)制。
redux中間件機(jī)制
import { createStore, applyMiddleware } from 'redux';
import reducers from './reducers';
const middlewares = applyMiddleware(middleware1, middleware2);
const store = createStore(reducers, middlewares);
所以說(shuō)redux-thunk是被傳入applyMiddleware方法中作為參數(shù)使用的,不難猜到applyMiddleware方法中一定有遍歷執(zhí)行參數(shù)的邏輯,我們來(lái)看看applyMiddleware的核心源碼:
export default function applyMiddleware(...middlewares) {
return function enhancer(createStore) {
return function enhancedCreateStore(...args) {
const store = createStore(...args)
let dispatch = () => {
thrownewError('此處省略n個(gè)字...')
}
const middlewareAPI = {
getState: store.getState,
dispatch: (...args) => dispatch(...args)
}
const chain = middlewares.map(function(middleware) {
return middleware(middlewareAPI)
})
dispatch = compose(...chain)(store.dispatch)
return {
...store,
dispatch,
}
}
}
}
export default function compose(...funcs) {
if (funcs.length === 0) {
return arg => arg
}
if (funcs.length === 1) {
return funcs[0]
}
return funcs.reduce(function(a, b) {
return function (...args) {
return a(b(...args))
}
})
}
在掌握了redux中間件實(shí)現(xiàn)原理之后, 我們?cè)賮?lái)看redux-thunk源碼就非常容易理解了。
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;

所以這里的next也就是第二次調(diào)用時(shí)的store.dispatch, 為了實(shí)現(xiàn)同一函數(shù)內(nèi)能執(zhí)行多次dispatch,我們會(huì)判斷如果action為函數(shù),則執(zhí)行action本身并把必要參數(shù)傳遞給它,否則則直接觸發(fā)dispatch,這樣我們就實(shí)現(xiàn)了支持action為函數(shù)并且支持異步多dispatch的功能了,讀到這還是非常感嘆其設(shè)計(jì)的優(yōu)雅和簡(jiǎn)潔,不經(jīng)讓筆者感嘆:學(xué)好函數(shù)式,走遍天下都不怕!
最后筆者準(zhǔn)備了一個(gè)基于React+redux+redux-thunk的實(shí)戰(zhàn)項(xiàng)目,github地址:
https://github.com/MrXujiang/redux_OA
感興趣的可以學(xué)習(xí)參考一下。
最后
如果想學(xué)習(xí)更多H5游戲, webpack,node,gulp,css3,javascript,nodeJS,canvas數(shù)據(jù)可視化等前端知識(shí)和實(shí)戰(zhàn),歡迎在公號(hào)《趣談前端》加入我們的技術(shù)群一起學(xué)習(xí)討論,共同探索前端的邊界。
