Redux-Middleware-原理解析

再學習redux的過程當中,Middleware這塊感受很燒腦,因此對它的原理進行整理redux


有一些比較基礎的先不整理,數組


以日誌中間件爲例閉包

//如下的這種寫法屬於柯里化的知識
const logger = state => next => action =>{
    console.log('dispatch', action);
    next(action);
    console.log('nextState',store.getState);
}

以上的代碼能夠解釋成app

var logger = function logger(state) {
    return function (next) {
        return function (action) {
            console.log('dispatch', action);
            next(action);
            console.log('nextState', store.getState);
        };
    };
};
//applyMiddleware 源碼
export default function applyMiddleware(...middlewares) {
  //假如說 middlewares 裏有三個mid1,mid2,mid3
  return (createStore) => (reducer, preloadedState, enhancer) => {
    const store = createStore(reducer, preloadedState, enhancer)
    let dispatch = store.dispatch
    let chain = []

    //一個保存了store狀態,和dispatch方法的對象 這個對應的就是logger 的store
    const middlewareAPI = {
      getState: store.getState,
      dispatch: (action) => dispatch(action)//經過閉包的形式引用外部的dispatch
    }
    //執行了middleware方法,返回了須要next參數的方法 的數組
    chain = middlewares.map(middleware => middleware(middlewareAPI))
    //假如chain 爲[f1,f2,f3,f4,f5,f6,f7]
    //那麼下面這句話的翻譯就是這樣   dispatch = f1(f2(f3(f4(f5(f6(f7(store.dispatch)))))))
    //就是將chain中的函數串聯到一塊兒,這種組合從最裏面開始執行,返回的結果做爲上一個函數的參數,一直向外執行
    //就是至關於從chain函數的最右側到最左側執行
    //compose(...chain) 返回的是一個匿名函數  function compose(...funcs)  funcs就是chain
    //return funcs.reduce((a, b) => (...args) => a(b(...args))) 這裏的args就是store.dispatch
    dispatch = compose(...chain)(store.dispatch)
    //dispatch = f1(f2(f3(f4(f5(f6(f7(store.dispatch)))))))
    //當調用dispatch的時候就依次執行
    return {
      ...store,
      dispatch// 這個是處理過的dispatch
    }
  }

}
chain = middlewares.map(middleware => middleware(middlewareAPI))

這裏能夠看出來,在日誌中間件中的第一層的store就是middlewareAPI
而且將第二層返回到chain的數組中
這就至關於當初的store => next => action =>{...}變成了next => action =>{...}函數

dispatch = compose(...chain)(store.dispatch)

function compose(...funcs) {
  if (funcs.length === 0) {
    return arg => arg
  }
  if (funcs.length === 1) {
    return funcs[0]
  }
  return funcs.reduce((a, b) => (...args) => a(b(...args)))
}

這一步至關於把chain數組中函數,經過處理獲得一種相似於層層嵌套的結構f1(f2(f3(f4(args))))
因此dispatch = A(B(C(store.dispatch))學習

單箇中間件較爲簡單,因此拿三個中間件作例子
經上面所述spa

//由於拋開store,剩下的中間件的結構相似於下面這種
function A1(next){
  return function A2(action){
    next(action)
  }
}

function B1(next){
  return function B2(action){
    next(action)
  }
}

function C1(next){
  return function C2(action){
    next(action)
  }
}
//dispatch = A(B(C(store.dispatch))
//這種結構會先執行最內部的函數,也就是C(store.dispatch)這一塊
//當執行了C 返回的是一個函數
function C2(action){
    store.dispatch(action)
}

//返回值最爲他的外層函數的參數next
next = function C2(action){
    store.dispatch(action)
}
//此時的結構相似於這種
dispatch = A(B(function C2(action) {
                    store.dispatch(action)
                }(action)
                )
            )
//接下來執行B,返回了
next = function C2(action){
    function C2(action){
        store.dispatch(action)
    }(action)
}
//此時的結構相似於這種
dispatch = A(function B2(action) {
                    function C2(action){
                        store.dispatch(action)
                    }(action)
                }(action)
            )
//接下來執行A,返回了
dispatch = function A2(action){
                function B2(action) {
                    function C2(action){
                        store.dispatch(action)
                    }(action)
                }(action)
            }(action)

最後返回新的store翻譯


總結日誌

  1. 調用applyMiddleware 傳入n箇中間件的數組
  2. 用一個middlewareAPI保存當前的store.getState,和dispatch所指向的函數
  3. 迭代中間件數組,並執行一遍,將middlewareAPI做爲最外層的store,而且返回一個至關於next函數的數組
  4. 將數組整理成嵌套的函數體,並將store.dispatch傳入最內側的函數的next,並返回通過處理的dispatch (dispatch是一個通過處理的函數,是一個嵌套了多層的函數,其最裏面調用的是store.dispatch)
  5. 返回一個新的store
相關文章
相關標籤/搜索