Redux源碼解析

Redux主要作的幾件事情

  • 生成一個全局惟一的state
  • 僅提供一種方法去修改state
  • 使用中間件增強dispatch函數
  • 提供listener在數據變化的時候執行相應的操做

使用閉包在createStore函數保存惟一的state

createStore.js

輸出:redux

{
    dispatch,
    subscribe,
    getState,
    replaceReducer,
    [$$observable]: observable
}
複製代碼

這些函數會調用到閉包裏面的一些變量,如currentState, currentReducer, currentListeners。api

僅提供dispatch去修改state

dispatch

做用:將action和state傳入reducer並修改對應的state,並執行listeners數組裏面的全部listener 核心就是這句數組

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

combineReducers.js

做用:將一堆reducer存在閉包裏面,最終返回一個總的reducer
輸入:一個對象,對象中每一個屬性對應一個reducerbash

{
    task: (state, action) => {
        switch (action.type) {
            case 'CHANGE_FILTER_STATUS':
                state.filterStatus = action.data
                return state
            default:
                return state;
        }
    }
}
複製代碼

核心代碼:閉包

// 將reducer存到閉包中
const finalReducers = {}
for (let i = 0; i < reducerKeys.length; i++) {
    const key = reducerKeys[i]
    
    if (process.env.NODE_ENV !== 'production') {
      if (typeof reducers[key] === 'undefined') {
        warning(`No reducer provided for key "${key}"`)
      }
    }
    
    if (typeof reducers[key] === 'function') {
      finalReducers[key] = reducers[key]
    }
}
 
// 輸出:一個總的recuder函數,做用爲遍歷全部的reducer,返回一個state
return function combination(state = {}, action) {
    let hasChanged = false
    const nextState = {}
    for (let i = 0; i < finalReducerKeys.length; i++) {
      const key = finalReducerKeys[i]
      const reducer = finalReducers[key]
      const previousStateForKey = state[key]
      const nextStateForKey = reducer(previousStateForKey, action)
      if (typeof nextStateForKey === 'undefined') {
        const errorMessage = getUndefinedStateErrorMessage(key, action)
        throw new Error(errorMessage)
      }
      nextState[key] = nextStateForKey
      hasChanged = hasChanged || nextStateForKey !== previousStateForKey
    }
    return hasChanged ? nextState : state
  }
複製代碼

經過applyMiddleware增強dispatch函數

核心代碼:app

const middlewareAPI = {
  getState: store.getState,
  dispatch: (...args) => dispatch(...args)
}
const chain = middlewares.map(middleware => middleware(middlewareAPI))
dispatch = compose(...chain)(store.dispatch)
複製代碼

其中compose其實就是使用array.reduce從右到左執行函數
compose核心代碼:ide

return funcs.reduce((a, b) => (...args) => a(b(...args)))
複製代碼

經過subscribe註冊listener

每次添加listener時都先深複製複製一份以前的listener
返回一個unsubscribe函數函數

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

用array.slice()方法來深複製ui

function ensureCanMutateNextListeners() {
    if (nextListeners === currentListeners) {
      nextListeners = currentListeners.slice()
    }
}

複製代碼

總結

經過分析redux的源碼,首先咱們能夠更好的理解咱們使用redux的時候,裏面具體發生了什麼事情,其次是能夠更清楚地看到各類redux的插件是如何加入到redux裏面的,對於咱們之後使用redux或者redux的插件會有幫助。
另外一方面,從代碼的組織上來看,能夠看到了裏面有不少閉包的使用,還有各類各樣的錯誤處理,以及簡潔的語法,對於自身代碼質量的提升也有必定的影響。spa

相關文章
相關標籤/搜索