Redux源碼分析(一)

Redux源碼分析(createStore)

使用redux都快3年了,到如今也沒認真去了解一下源碼罪過啊,因此須要對它進行一些分析和學習,一方面能更好的去使用它,另外一方面也學習一下該框架的設計思路,首先咱們看到 redux/src/index.js 文件git

export {
  createStore,
  combineReducers,
  bindActionCreators,
  applyMiddleware,
  compose,
  __DO_NOT_USE__ActionTypes
}
複製代碼

因此主要部分也就是上面幾個函數,咱們下面一點點去分析每個功能點github


createStore

其實該文件有着大量的註釋了,你們能夠先簡單的看看代碼中的註釋瞭解一遍。 其實createStore就是返回了一個對象,這個對象只有幾個方法而已,而咱們經常使用的就是dispatchsubscribegetState這三個了redux

* Creates a Redux store that holds the state tree.
 * The only way to change the data in the store is to call `dispatch()` on it.
複製代碼

該函數的做用呢就是創建一個store(廢話嘛),那麼什麼是store呢?個人理解 就是一個倉庫,存着整個程序的狀態,且只能有一個,就是用這一個store搞定項目中的所有狀態,固然不論多大的項目,通通只有這一個,弄兩個確定很差使,而且只有一個路子去修改裏面的數據,那麼就是調用dispatch()api

function createStore(reducer, preloadedState, enhancer)
複製代碼

能夠看到函數體主要三個參數,簡單說下數組

  • reducer:它是一個函數能夠表達爲:(preState,action) => newState就是說根據action和以前的狀態,返回一個的狀態(這裏的新是新構建,而不是修改過,這點切記)
  • preloadedState:字面理解便可,預先加載的狀態,即初始狀態
  • enhancer:這個須要拿出篇幅來講了,加強劑,加強createStore
if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') {
    enhancer = preloadedState
    preloadedState = undefined
  }
複製代碼

也容易理解,在只有兩個參數的狀況,而且第二個爲funcion的時候,那麼第二個參數就是enhancer了,交互一下參數位置bash

if (typeof enhancer !== 'undefined') {
    if (typeof enhancer !== 'function') {
      throw new Error('Expected the enhancer to be a function.')
    }

    return enhancer(createStore)(reducer, preloadedState)
  }
複製代碼

對enchancer類型判斷,能夠看到enhancer就是將store傳入,在內部處理以後再將store返回來,繼續傳入reducer和初始狀態進行構建app

let currentReducer = reducer
  let currentState = preloadedState
  let currentListeners = []
  let nextListeners = currentListeners
  let isDispatching = false

  function ensureCanMutateNextListeners() {
    if (nextListeners === currentListeners) {
      nextListeners = currentListeners.slice()
    }
  }
複製代碼

創建一些變量保存reducer,state,以及訂閱器保存在nextListeners中,ensureCanMutateNextListeners至關於每次對當前的訂閱器進行備份,由於每次訂閱一個listener的時候都是對nextListeners數組進行添加框架

function subscribe(listener) {
    if (typeof listener !== 'function') {
      throw new Error('Expected the listener to be a function.')
    }

    if (isDispatching) {
      throw new Error(
        'You may not call store.subscribe() while the reducer is executing. ' +
          'If you would like to be notified after the store has been updated, subscribe from a ' +
          'component and invoke store.getState() in the callback to access the latest state. ' +
          'See https://redux.js.org/api-reference/store#subscribe(listener) for more details.'
      )
    }

    let isSubscribed = true

    ensureCanMutateNextListeners()
    nextListeners.push(listener)

    return function unsubscribe() {
      if (!isSubscribed) {
        return
      }

      if (isDispatching) {
        throw new Error(
          'You may not unsubscribe from a store listener while the reducer is executing. ' +
            'See https://redux.js.org/api-reference/store#subscribe(listener) for more details.'
        )
      }

      isSubscribed = false

      ensureCanMutateNextListeners()
      const index = nextListeners.indexOf(listener)
      nextListeners.splice(index, 1)
    }
  }
複製代碼

訂閱器,註冊監聽函數,每個listener都是一個func,而且返回了一個取消註冊監聽的函數unScribe,用於刪除listener,其實就是將一個個的函數添加到數組中,以後每次在store發生變化的時候(其實也就是調用dispatch的時候)就會觸發它~async

function dispatch(action) {
    if (!isPlainObject(action)) {
      throw new Error(
        'Actions must be plain objects. ' +
          'Use custom middleware for async actions.'
      )
    }

    if (typeof action.type === 'undefined') {
      throw new Error(
        'Actions may not have an undefined "type" property. ' +
          'Have you misspelled a constant?'
      )
    }

    if (isDispatching) {
      throw new Error('Reducers may not dispatch actions.')
    }

    try {
      isDispatching = true
      currentState = currentReducer(currentState, action)
    } finally {
      isDispatching = false
    }

    const listeners = (currentListeners = nextListeners)
    for (let i = 0; i < listeners.length; i++) {
      const listener = listeners[i]
      listener()
    }

    return action
  }
複製代碼

上面呢就是這裏比較重要的dispatch函數了,其實很是簡單,主要就是它:函數

currentState = currentReducer(currentState, action)
複製代碼

將當前的所有狀態和action傳入reducer,獲得新的state,這樣就完成了state的狀態更新了,以後再去遍歷所有的listeners,從而在各個listeners的內部去更新view,完成整個流程(返回值其實仍是這個action對象),其實以上內容和三個函數應該是redux的核心內容了,下面用一種簡單的總結來表達一下store(借鑑的阮一峯的)

const createStore = (reducer) => {
  let state;
  let listeners = [];

  const getState = () => state;

  const dispatch = (action) => {
    state = reducer(state, action);
    listeners.forEach(listener => listener());
  };

  const subscribe = (listener) => {
    listeners.push(listener);
    return () => {
      listeners = listeners.filter(l => l !== listener);
    }
  };

  dispatch({});

  return { getState, dispatch, subscribe };
};
複製代碼

而該文件還有兩個函數分別是

function replaceReducer(nextReducer)
function observable()
複製代碼

第一個很明顯替換整個reducer用,在一些熱加載場景應該會用到 而第二個暫時還不太理解做者意圖,用觀察者替換訂閱發佈嗎?暫時先不去想 以上就是整個createStore的源碼分析~

更多內容與討論能夠參考個人github.com/jinjiaxing/…

相關文章
相關標籤/搜索