【源碼解析】redux-thunk

瞭解了Redux原理以後,我很好奇Redux中間件是怎麼運做的,因而選了最經常使用的redux-thunk進行源碼分析。javascript

這次分析用的redux-thunk源碼版本是2.2.0,redux源碼版本是3.7.2。而且須要瞭解Redux原理java

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 = []

    //暴露給中間件的API,因此redux-thunk可使用形如return (dispatch, getState)=>{}
    const middlewareAPI = {
      getState: store.getState,
      dispatch: (action) => dispatch(action)
    }
    //將暴露的API給中間件,調用中間件函數,生成中間件返回值函數(爲何返回值是函數?不是函數下面的compose()就報錯了)
    chain = middlewares.map(middleware => middleware(middlewareAPI))
    //組合所有中間件的返回值函數, chain是中間件返回值函數們
    //而後reduce起來的函數返回的也是函數,將store原來的dispatch傳進去,dispatch函數也是接受一個action並返回一個action,做爲中間件鏈的頭部
    dispatch = compose(...chain)(store.dispatch)

    return {
      ...store,
      dispatch
    }
  }
}

能夠看到redux主要作了如下事情:app

  1. 對中間件們使用map,將dispatchgetState傳遞進去
  2. 使用compose將中間件組合起來,最後傳入原生的store.dispatch

compose函數則是簡單的將中間件進行串聯調用函數

//compose(funcA, funcB, funcC) 等於 (args)=>funcA(funcB(funcC(args)))
export default 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)))
}

最後咱們回到redux-thunk源碼分析

redux-thunk的代碼很短,只有短短14行spa

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;

它對外暴露的是const thunk = createThunkMiddleware();,也就是({dispatch, getState})=>{...}這個函數。code

而後經chain = middlewares.map(middleware => middleware(middlewareAPI))傳入dispatchgetStatechain裏面是next=>{...},進行compose中間件

compose(a,b,c)的返回值是函數(...args)=>a(b(c(...args))),這個函數經調用,傳入參數store.dispatch,以後action會在中間件鏈上進行傳遞,只要保證每一箇中間件的參數是action而且將action傳遞給下一個中間件。ip

具體到redux-thunk中,它先檢查action是不是函數,通常的action都是plain object,若是是函數就應該是由thunk處理。若是不是,傳遞給nextnext就是下一個中間件。

若是是函數,則調用這個函數並將dispatch, getState, extraArgument傳入。這也就是爲何咱們須要將thunk action生成函數(注意action和action生成函數的區別)寫成() => (dispatch, getState) => {...},傳入redux-thunk的action就是(dispatch, getState)=>{...}這個函數

相關文章
相關標籤/搜索