redux中間件探祕

從redux-thunk引出思考

在使用redux-thunk進行異步action書寫的時候,我常常好奇redux到底如何運做,讓asyncAction成爲可能react

爲了探究,咱們必須看一下redux-thunk的源碼了。幸運的是redux-thunk的源碼不多。。。至於爲何,下面立馬講解。es6

redux-thunk的源碼

// 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

咱們使用createStore api建立store的時候發生了什麼

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上。函數

applyMiddleware api如何實現中間件操做的。

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中間件了。

相關文章
相關標籤/搜索