對於Redux源碼的一些理解

Redux很早前看過源碼,不得不說Redux是一個有用的架構,接觸過Redux對於以後理解React-Redux有很大的幫助。最近學習了一段時間後打算從新學習下,一方面爲了總結和概括,另外一方面分享給你們,若是有什麼不足之處但願各位大牛的糾錯和指正。本文主要包含以下幾個分析點:javascript

  • applyMiddleware
  • compose
  • thunk中間件
// 該文件的核心函數部分共傳入了三個參數
// reducer, preloadedState, enhancer
function createStore(reducer, preloadedState, enhancer){
    ...
    if (typeof enhancer !== 'undefined') {
        return enhancer(createStore)(reducer, preloadedState)
    }
    ...
}
複製代碼

createStore方法的做用是用來建立一個倉庫來存放state,subscribe,reducer以及dispatch,state用來存放數據的地方,經過store.getState()來獲取;subscribe用來加入監聽函數,當頁面數據改變的時候會進行觸發,dispatch用來派發action,根據不一樣的類型匹配不一樣的reducer,繼而進行state數據的更新,具體能夠參考阮一峯老師的博客 Redux 入門教程html

其中enhancer函數的做用顧名思義就是用來擴展增強的,這個函數的存在使得能夠隨意的加入早就想要的中間件,從而更加方便快捷,這裏的增強函數主要是applyMiddlewarejava

applyMiddleware

這裏使用連續箭頭函數,簡單明瞭更重要的一點是造成了閉包,閉包的存在使得內部的變量能夠很自由的訪問外部被多個return嵌套的變量, 從而使得每一箇中間件都得到middlewareAPI參數,引用外部的dispatch變量,這樣避免了若是存在一箇中間件修改了dispatch致使後面一系列的問題。
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) // 經過閉包引用外部的dispatch變量
    }
    // 將middlewareAPI傳入中間件,使得每一箇中間件都得到{getState,dispatch}參數,而因爲閉包的緣由,咱們就能夠在中間件當中獲取最新的store以及引用外部更新的dispatch變量。
    // @return 返回包含(next) => (action) => {....}的數組
    chain = middlewares.map(middleware => middleware(middlewareAPI))
    // 建立加強功能的dispatch
    dispatch = compose(...chain)(store.dispatch)

    return {
      ...store,
      dispatch
    }
  }
}
複製代碼

thunk中間件

以thunk中間件爲例,當須要派發的action是異步函數而不是對象的時候須要這個中間件,則此時chain即爲 [(next)=>(action)=>{...}, ....], 若是action爲函數則直接執行該函數,而且傳入 dispatchgetSate這兩個參數,不然執行next方法直到最後next函數爲dispatch進行action派發。
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;
複製代碼

compose

理解compose方法首先須要瞭解reduce,reduce()方法接收一個函數做爲累加器,數組中的每一個值(從左到右)開始縮減,最終計算爲一個值,因此最終的形式是a(b(c(d...(...args))))redux

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)))
}
複製代碼

以前chain返回包含(next) => {...}的thunk,logger中間件數組,從而獲得a_middleware方法裏的next方法就是b_middleware,b_middleware方法裏的next方法是c_middleware,以此類推,根據applyMiddleware.jscompose(...chain)(store.dispatch)以及chain返回值能夠知道, 最後的next參數是dispatch,大概步驟以下:數組

  • 第一步:當咱們把store.dispatch傳入c_middleware時,這時就把store.dispatch傳給了 c_middleware的next變量,返回一個(action)=>{next=store.dispatch}[1]函數;
  • 第二步:接下來就是把[1]傳給b_middleware的中間件的next,這時候中間件b_middleware內部的next就變成(action)=>{[1]}[2], 當執行b_middleware的時候,會進入c_middleware;
  • 第三步:接下來就是把[2]的結果傳遞給a_middleware, (action)=>(action)=>{[1]}傳遞給a-middleware的next變量,當執行a_middleware的時候會進入b_middleware。

從下面大概例子能夠看出disatch: (...args) => dispatch(...args)的好處,dispatch隨時隨地隨着dispatch = compose(...chain)(store.dispatch)更新而更新,從而當傳入爲方法的時候,也不會忽略其餘中間件,再次dispatch的時候會流過全部thunk以後的中間件。閉包

1.
a_middleware(b_middleware){
    ...
    b_middleware = (action) => (action) => {store.dispatch函數}
    return (action) => b_middleware(action)
    ...
}
dispatch = (action) => {
    if (typeof action === 'function') {
      return action(dispatch, getState, extraArgument);
    }
    return b_middleware(action)
}
2.
b_middleware(c_middleware){
    ...
    c_middleware = (action) => {store.dispatch函數}
    return (action) => c_middleware(action)
    ...
}
dispatch = (action) => {
    return c_middleware(action)
}
3.
c_middleware(store.dispatch){
    return (action) => {store.dispatch函數}
}
dispatch = (action) => {store.dispatch函數}
複製代碼

總結

1.首先將store.getStatestore.dispatch經過閉包的方式使得中間件能夠訪問;架構

2.其次,經過compose函數操做,對next進行賦值,使得中間件按順序依次執行;app

3.最後,返回一個dispatch函數,能夠經過傳入action參數,使得中間件按順序依次執行,若是action爲函數則直接執行該函數,而且傳入dispatch和getSate參數。異步

總之使用redux進行狀態管理極大地提升了工做效率,讓數據更好地被管理。函數

相關文章
相關標籤/搜索