redux中間件原理

image

中間件執行順序

應用了以下的中間件: [A, B, C],git

整個執行 action 的過程爲 A -> B -> C -> dispatch -> C -> B -> Agithub

==通過applyMiddleware方法後的dispatch方法是相似下面,某處調用store.dispatch則傳入action, 而後按洋蔥模型來執行==redux

(action) => {
    //...
    next(action)
    //...
}

==最右側的 next(action)返回的是應用傳入的action==, 該行爲是由redux createStore源碼中dispatch方法返回值決定的,不過通常都會 return next(action),數組

前面的中間件的next(action)的值都是後一箇中間件的返回值閉包

小例子

const middleware1 = ({getState, dispatch}) => next => action => {

    console.log(`middleware1 before next action `)
    console.log(next)
    next(action)
    console.log(`middleware1 after next action `)
}
const middleware2 = ({getState, dispatch}) => next => action => {

    console.log(`middleware2 before next action `)
    console.log(next)
    next(action)
    console.log(`middleware2 after next action `)
}
const middleware3 = ({getState, dispatch}) => next => action => {

    console.log(`middleware3 before next action `)
    console.log(next)
    next(action)
    console.log(`middleware3 after next action `)
}



const sagaMiddleware = createSagaMiddleware()
const store = createStore(reducer, applyMiddleware(middleware1, middleware2, middleware3))

被中間件包裝過的dispatch方法

是相似於func1(func2(store.dispatch))這種形式的函數app

==next方法實際上是此中間件右邊中間件的這個方法,你要給它傳action。==函數

(action) => {
    //func2中的next是store.dispatch
    next(action);
}

==實際的調用順序是和傳入中間件順序相反的==spa

let store = applyMiddleware(Middleware1,Middleware2,Middleware3)(createStore)(rootReducer);

實際的執行是次序是store.dispatch->Middleware3->Middleware2->Middleware1。

middlewareAPI中的dispatch被普通函數包裝了一下

var middlewareAPI = {3d

getState: store.getState,
dispatch: (action) => dispatch(action)

};rest

並無直接使用dispatch:dispatch,而是使用了dispatch:(action) => dispatch(action),其目的是==若是使用了dispatch:dispatch,那麼在全部的Middleware中實際都引用的同一個dispatch(閉包),若是存在一箇中間件修改了dispatch,就會致使後面一下一系列的問題==,可是若是使用dispatch: (action) => dispatch(action)就能夠避免這個問題。

compose源碼

export default function compose(...funcs) {
  if (funcs.length === 0) {
    return arg => arg
  }

  if (funcs.length === 1) {
    return funcs[0]
  }

  const last = funcs[funcs.length - 1]
  const rest = funcs.slice(0, -1)
  return (...args) => rest.reduceRight((composed, f) => f(composed), last(...args))
}

applyMiddleware 源碼

這裏chain是函數數組。而後執行compose(...chain)(store.dispatch)。
chain數組的最後一個函數接收store.dispatch函數作爲參數,仍是返回一個函數,接收action做爲參數。這個返回的函數是chain中倒數第二個函數的參數,也就是參數next

[
    next => action => {
        
        return next(action)
    }
]
export default function applyMiddleware(...middlewares) {
  return (createStore) => (reducer, preloadedState, enhancer) => {
    var store = createStore(reducer, preloadedState, enhancer)
    var dispatch = store.dispatch
    var chain = []

    var middlewareAPI = {
      getState: store.getState,
      dispatch: (action) => dispatch(action)
    }
    chain = middlewares.map(middleware => middleware(middlewareAPI))
    
    dispatch = compose(...chain)(store.dispatch)

    return {
      ...store,
      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;

參考

https://github.com/MrErHu/blo...

https://zhuanlan.zhihu.com/p/...

https://zhuanlan.zhihu.com/p/...

相關文章
相關標籤/搜索