Redux原始碼解讀--(5)createStore

Run_youngman發表於2018-01-17

下面介紹最後一個函式,CreateStore.先上一個基本的用法吧。

const store = createStore(reducers, state, enhance);
這個enhance就是 applyMiddleware(...middleware),可以參見上一篇

下面上原始碼吧。首先說一下,這麼多程式碼其實首次執行的邏輯很簡單,大部分程式碼都是定義了一個函式去等待呼叫的,真正就只是呼叫了一個預設的dispatch方法,初始化了一下下currentState.

export default function createStore(reducer, preloadedState, enhancer) {
  if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') { //第一步操作表明,可以不傳第二個引數,如果不傳則置為undefined,將enhancer過渡到第三個引數
    enhancer = preloadedState
    preloadedState = undefined
  }

  if (typeof enhancer !== 'undefined') {
    if (typeof enhancer !== 'function') {   //enhancer必須為函式
      throw new Error('Expected the enhancer to be a function.')
    }

    return enhancer(createStore)(reducer, preloadedState)  //如果傳遞enhancer,則把createStore作為引數傳遞過去,我在上一篇說過,第三個引數不傳也可以,因為這裡根本就不會接收!applymiddleware中會將createStore執行並返回。
  }

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

  let currentReducer = reducer
  let currentState = preloadedState   //當前的state
  let currentListeners = []     //當前的listeners
  let nextListeners = currentListeners
  let isDispatching = false   //是否正在分發

  function ensureCanMutateNextListeners() {    //具體這裡為什麼會淺拷貝一個陣列出來我也說不上來,有知道的麻煩幫忙解答一下
    if (nextListeners === currentListeners) {
      nextListeners = currentListeners.slice()  //只是拷貝了一份
    }
  }

  function getState() {  //返回當前state
    return currentState
  }

  
  function subscribe(listener) {
    if (typeof listener !== 'function') {  //監聽器要是函式
      throw new Error('Expected listener to be a function.')
    }

    let isSubscribed = true

    ensureCanMutateNextListeners()  
    nextListeners.push(listener)

    return function unsubscribe() {  //返回一個函式用來解除監聽
      if (!isSubscribed) {
        return
      }

      isSubscribed = false

      ensureCanMutateNextListeners()
      const index = nextListeners.indexOf(listener)
      nextListeners.splice(index, 1)    //從listeners中去除
    }
  }

  function dispatch(action) {
    if (!isPlainObject(action)) {   //action必須是個物件{type:'XXX'}
      throw new Error(
        'Actions must be plain objects. ' +
        'Use custom middleware for async actions.'
      )
    }

    if (typeof action.type === 'undefined') {  //物件必須有type屬性(唯一確定一個action,不能重複)
      throw new Error(
        'Actions may not have an undefined "type" property. ' +
        'Have you misspelled a constant?'
      )
    }

    if (isDispatching) {   //不能同時執行兩個dispatch
      throw new Error('Reducers may not dispatch actions.')
    }

    try {
      isDispatching = true
      currentState = currentReducer(currentState, action)    //不論第一次傳入currentState是否有值,都會根據第一次的reducer返回預設值
      //比如首次執行createStore就會傳入一個幾乎不會存在於reducer的case中的型別,這樣就可以返回第一次傳入reducer的預設值了。
    } finally {
      isDispatching = false   //放開dispatch入口
    }

    const listeners = currentListeners = nextListeners
    for (let i = 0; i < listeners.length; i++) {
      const listener = listeners[i]
      listener()   //將監聽器執行一遍
    }

    return action
  }

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

    currentReducer = nextReducer  //更換當前的reducer,並且執行預設dispatch返回預設值。
    dispatch({ type: ActionTypes.INIT })
  }

//由於一個正規的reducer都會返回一個預設值,執行這一步(ActionTypes真的很少會被定義),為了返回reducer的預設值。
  dispatch({ type: ActionTypes.INIT })

  return {
    dispatch,
    subscribe,
    getState,
    replaceReducer
  }
}

大概原始碼就這些,通過上一篇我們可以發現這個middleware是可以compose的,也就是說可以組合,來達到強化dispatch的目的。那麼是不是可以通過compose這個applymiddleware來做些什麼呢?

提升:

我們發現在createStore中並沒有直接說applymiddleware,而是使用了enhancer這個名詞,增強器。

那麼我就認為applymiddleware其實是一個增強器,那肯定不止這一個嘍。比如:

const store = createStore(combineReducers({ routering: routerReducer }),
    {},
    composeEnhancers(  //這個函式也是一個類庫中引用的
        applyMiddleware(myTestMidware_delay, ...middleware,myTestMidware),
        myEhancer
    )
);
還是那個compose的套路,我傳遞的引數是createStore這個函式,他返回一個createStore函式,然後在下一個函式中把上一個傳入的createStore執行一下,這就是我們要做的。這裡增強的是createStore這個函式。

const myEhancer = (createstore)=> (reducer, preloadedState) => {
    const store = createstore(reducer, preloadedState);   //接收返回的store,並繼續增強。
    const dispatch = (action)=>{
        console.log('我是一個Enhancer,action為:',action);
        return store.dispatch(action);
    }
    return {...store,dispatch};
}
由於createStore不止執行性的操作,所以這裡的return 不可以省略,每次返回的都是自己增強過的store。

通過增強器也可以達到增強dispatch的效果,所以能通過middleware實現的,都可以通過enhancer實現。

最後,誰知道那個ensureCanMutateNextListeners是幹嘛的啊,留言,thx.




相關文章