在使用redux-thunk進行異步action書寫的時候,我常常好奇redux到底如何運做,讓asyncAction成爲可能react
爲了探究,咱們必須看一下redux-thunk的源碼了。幸運的是redux-thunk的源碼不多。。。至於爲何,下面立馬講解。es6
// redux-thunk source code 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的返回函數,就是redux所須要適應的中間件。express
以es6箭頭語法看來可能比較麻煩,咱們能夠試着把這個代碼直接轉成es5的形式看看。redux
function createThunkMiddleware(extraArgument) { return function (storeOrFakeStore) { var dispatch = storeOrFakeStore.dispatch; var getState = storeOrFakeStore.getState; return function (next) { return function (action) { return action(dispatch, getState, extraArgument); } return next(action); } }; }
從這個源碼能夠看出,自己中間件是會接受當前store或者一個fakeStore(這個fakeStore可能僅僅只承載了store的兩個api,dispatch和getState),並將dispatch和getState這兩個store的方法傳進可能執行異步操做的action函數裏。這樣,action完成異步操做之後,一樣被賦予了dispatch的權利,就可以將狀態經過action流轉到下一個場景了。api
那同窗們又會問了,這個next是個啥?恩,其實這個next其實就是下一個要處理action的中間件,畢竟中間件是一個接着一個的對吧。若是你們寫過koa或者express應該對這個next會熟悉不少。app
接下來咱們來看看react源碼中的createStore模塊是怎麼應用中間件的。koa
applyMiddleware一樣也是一個工廠,若是讀者您用過redux中間件的話,你應該知道redux建立store是怎樣建立的異步
const store = createStore( reducer, applyMiddleware(...middleware) )
如下是createStore的源碼,咱們只看相關的一部分async
export default function createStore(reducer, preloadedState, enhancer) { if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') { enhancer = preloadedState preloadedState = undefined } if (typeof enhancer !== 'undefined') { if (typeof enhancer !== 'function') { throw new Error('Expected the enhancer to be a function.') } return enhancer(createStore)(reducer, preloadedState) } ... }
結合store的聲明和使用,咱們能夠知道redux的第三個參數能夠接受一個叫作加強器的東西,若是存在加強器,則直接調用加強器方法,返回新的store並加強redux的功能。而使用中間件的時候,redux將存在的applyMiddleware工廠方法做爲加強器應用在了redux上。函數
export default function applyMiddleware(...middlewares) { return (createStore) => (reducer, preloadedState, enhancer) => { const store = createStore(reducer, preloadedState, enhancer) let dispatch = store.dispatch let chain = [] const middlewareAPI = { getState: store.getState, dispatch: (action) => dispatch(action) } chain = middlewares.map(middleware => middleware(middlewareAPI)) dispatch = compose(...chain)(store.dispatch) return { ...store, dispatch } } }
applyMiddleware工廠函數對傳入的中間件進行了compose操做,使中間件互相之間呈嵌套的形式,這樣在中間件裏的next函數就能夠next()執行下去了。。。新的dispatch會從第一個中間件開始觸發,這樣,在咱們調用store.dispatch的時候,就會將中間件走一遍了。
// compose函數 export default function compose(...funcs) { if (funcs.length === 0) { return arg => arg } if (funcs.length === 1) { return funcs[0] } // 若是存在多箇中間件,直接使用reduce方法將各個中間件嵌套起來。 // 因而咱們在使用中間件的時候就要注意了,中間件本質是一個攔截操做 // 若是咱們有兩個中間件對某一個類型的action前後作了攔截,咱們必須注意 // 在createStore的時候插入中間件的順序,中間件方法的執行是有序的。 return funcs.reduce((a, b) => (...args) => a(b(...args))) }
怎麼樣,redux的源碼簡單嗎?簡單到同窗們也能本身開發中間件,如今你們本身也能夠動手寫本身的react中間件了。