redux v3.7.2源碼解讀與學習之 applyMiddleware

redux是什麼、有什麼做用,解決什麼問題,若是你還不知道,請先去這裏: redux中文文檔git

下面的文章適合對redux有必定理解和使用經驗的人github

項目github地址:github.com/wangweiange…redux

若是你以爲對你有幫助的話記得給我一個star呢數組


applyMiddleware有什麼用:

使用包含自定義功能的 middleware 來擴展 Redux 是一種推薦的方式。promise

Middleware 可讓你bash

包裝 store 的 dispatch 方法
來達到你想要的目的。

同時, middleware 還擁有「可組合」這一關鍵特性。多個 middleware 能夠被組合到一塊兒使用,造成 middleware 鏈。app

其中標紅色的部分是咱們很經常使用到的,例如redux-thunkredux-promise插件。異步


若要很好的理解applyMiddleware咱們歸入redux-thunk源碼來分析:函數

先看看 applyMiddleware的源碼:
學習

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 接收多個參數,並返回一個以createStore爲參數的function,此function通過一系列的處理以後返回了 createStore裏面的全部方法和重寫的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;複製代碼

也是很是的簡潔接收一個extraArgument參數,返回一個{ dispatch, getState }爲參數的function,即最終返回的是這個函數:

從源碼中能夠看出 thunk 最終的值爲 這個function
({ dispatch, getState }) => next => action => {
    if (typeof action === 'function') {
      return action(dispatch, getState, extraArgument);
    }

    return next(action);
  };複製代碼

讓咱們來簡化一下它用通俗的方式改寫以下,

咱們把它命名爲AAA
,以方便與下面的理解:

//用通俗的代碼重寫
let AAA = function (opt) {
    var dispatch = opt.dispatch,
        getState = opt.getState;
    return function (next) {
        return function (action) {
            if (typeof action === 'function') {
                return action(dispatch, getState, extraArgument);
            }
            return next(action);
        };
    };
};複製代碼

能夠很清晰的看出,傳入了dispatch和getState,返回了一個函數,並判斷函數的action參數是否爲function作不一樣的處理,其中標識爲紅色的爲實現異步的核心。

也許仍是不能理解因此然,下面讓咱們來理清它。


來看看createStore,applyMiddleware 加上 redux-thunk 以後的調用方式:

import thunk from 'redux-thunk'
import { createStore,applyMiddleware } from './redux'
const store = createStore(
    reducers,
    applyMiddleware(thunk)
)複製代碼

咱們來給一個reducers測試案例來分析源碼的走向,完整代碼以下:

import thunk from 'redux-thunk'
import { createStore,applyMiddleware } from './redux'

const ADD_TODO = 'ADD_TODO'

function reducers(state = [], action) {
  switch (action.type) {
    case 'ADD_TODO':
      return state.concat([ action.text ])
    default:
      return state
  }
}
// 建立 Redux 的 store 對象
const store = createStore(
    reducers,
    applyMiddleware(thunk)
)
console.log(store.getState())複製代碼


下面我經過在代碼中註釋的方式來講明運行流程:

//此時 ...middlewares = [ AAA ]   AAA在上面有說明
export default function applyMiddleware(...middlewares) {

    //返回一個函數 惟一的參數爲 createStore,也就是redux中的createStore函數
  return (createStore) => (reducer, preloadedState, enhancer) => {

    //這裏相執行了createStore方法 傳了3個參數,
    //這三個參數從createStore.js 中的 return enhancer(createStore)(reducer, preloadedState) 得來,能夠看出傳來的參數只有2個
    //所以也就不會再執行createStore.js中的 enhancer函數
    const store = createStore(reducer, preloadedState, enhancer)

    //這裏獲得了store,拿取createStore.js 中的dispatch函數 存儲在dispatch臨時變量中
    let dispatch = store.dispatch

    //由於 ...middlewares 是一個數組,臨時存儲
    let chain = []

    //包裝 getState 和 dispatch 兩個方法
    const middlewareAPI = {
      getState: store.getState,
      dispatch: (action) => dispatch(action)
    }

    /*
    循環調用
    體如今案例中時 middlewares 的值爲 [AAA] 所以運行一次
    返回的chain爲 [ AAA(middlewareAPI)  ], 能夠看出middlewareAPI值正是AAA函數須要的兩個參數
    體如今案例中此時 chain 值爲:
    [
        function (next) {
            return function (action) {
                if (typeof action === 'function') {
                    return action(dispatch, getState, extraArgument);
                }
                return next(action);
            };
        },
    ]
     */
    chain = middlewares.map(middleware => middleware(middlewareAPI))

    /*
    這段代碼運行完以後會獲得新的dispatch
    體如今案例中下面這段代碼返回值dispatch爲:
    function (action) {
                if (typeof action === 'function') {
                    return action(dispatch, getState, extraArgument);
                }
                return store.dispatch(action);
     };
    這裏的面的 next 值爲 store.dispatch        
     */
    dispatch = compose(...chain)(store.dispatch)

    //最終返回新的createStore方法,重寫了dispatch,其餘的都沒有變
    return {
      ...store,
      dispatch
    }
  }
}複製代碼


根據以上的分析咱們來給一個異步的actions案例,並dispatch調用:

function actions(){
    return (dispatch)=>{    
        dispatch({
                type: ADD_TODO,
                text: 'Read the docs'
            })
    }
}

//使用redux-think處理以後的dispatch觸發actions
store.dispatch(actions())複製代碼


根據以上的分析咱們知道最終處理以後返回的dispatch值爲:

function (action) {
    if (typeof action === 'function') {
        return action(dispatch, getState, extraArgument);
    }
    return store.dispatch(action);
};複製代碼


當調用actions()以後咱們能夠明顯的看出 typeof action === 'function' 爲真
所以走是return action(dispatch, getState, extraArgument);,再去觸發reducers函數

最終經過 currentState = currentReducer(currentState, action) 從而改變惟一的store狀態數據

通過以上的分析就能很好的理解alpplyMiddleware這個方法和redux-thunk的主要做用了。


接下來咱們進入到redux的最後一個方法 bindActionCreators

redux v3.7.2源碼解讀與學習之 bindActionCreators



關注個人博客:zane的我的博客

原文地址:redux v3.7.2源碼解讀與學習之 applyMiddleware

相關文章
相關標籤/搜索