Redux源碼學習

何為Redux,為什么Redux之類的概念東西我這邊就不重復贅述了,可進入Redux官網(wǎng)查閱,以下是我在學習Redux的源碼的一些個人總結(jié).

我們可以先看看官方的文檔,都有哪些API,從中也可以看出Redux中的一些方法是如何演化出來的.我們先看看index.js文件中的內(nèi)容,代碼有省略部分,最好是拿著源碼一起看,Redux本身代碼量并不大,只是其中用了很多的函數(shù)柯里化的方式,看著會比較晦澀

// index.js
export {
  createStore,
  combineReducers,
  bindActionCreators,
  applyMiddleware,
  compose
}

從以上代碼可以看出來,就是Redux提供的API

createStore
import isPlainObject from 'lodash/isPlainObject'
import $$observable from 'symbol-observable'

/**
 *這就是初始化store狀態(tài)樹的action type
 */
export const ActionTypes = {
  INIT: '@@redux/INIT'
}

/**
 * 此函數(shù)接受三個參數(shù),第一個參數(shù)是一個函數(shù),就是我們的reduce函數(shù),返回一個state
 */
export default function createStore(reducer, preloadedState, enhancer) {
  /**當preloadedState為函數(shù)且enhancer不存在時,將preloadedState賦值給enhancer并且將createStore傳*入此函數(shù)
*/
  if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') {
    enhancer = preloadedState
    preloadedState = undefined
  }

  if (typeof enhancer !== 'undefined') {
    if (typeof enhancer !== 'function') {
      throw new Error('Expected the enhancer to be a function.')
    }
/**
*此處返回store提供的一些方法,如此處最后返回對象,只是其中的dispatch不一樣,由applyMidware方法返回的組合函數(shù)而得到
*/
    return enhancer(createStore)(reducer, preloadedState)
  }

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

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

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

  /**
   * 讀取當前整個狀態(tài)樹
   */
  function getState() {
    return currentState
  }

  /**
   * dispatch訂閱方法,當調(diào)用此方法時會在事件監(jiān)聽器中加入監(jiān)聽函數(shù),當dispatch了一個action時,所有訂  
 *閱的方法都會執(zhí)行,此方法執(zhí)行完成會返回一個取消訂閱方法,用于取消訂閱事件
   */
  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)
    }
  }

  /**
   * dispatch函數(shù)接受一個為對象的參數(shù),其中必須包含一個type屬性,會將新的state賦值給currentState,并且會執(zhí)行所有subscribe過的函數(shù),并返回當前的action
   */
  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.')
    }
    /** 改變當前dispatching狀態(tài)為true,并且將更改后的state賦值給當前state
    */
    try {
      isDispatching = true
      currentState = currentReducer(currentState, action)
    } finally {
      isDispatching = false
    }
  // 當觸發(fā)dispatching函數(shù)時,所有訂閱的函數(shù)都會被觸發(fā)
    const listeners = currentListeners = nextListeners
    for (let i = 0; i < listeners.length; i++) {
      const listener = listeners[i]
      listener()
    }

    return action
  }

  /**
   * 此方法會將傳入的reducer替換當前的reducer并進行Store初始化
   */
  function replaceReducer(nextReducer) {
    if (typeof nextReducer !== 'function') {
      throw new Error('Expected the nextReducer to be a function.')
    }

    currentReducer = nextReducer
    dispatch({ type: ActionTypes.INIT })
  }

  /**
   *不直接提供給開發(fā)者使用
   */
  function observable() {
    const outerSubscribe = subscribe
    return {

      subscribe(observer) {
        if (typeof observer !== 'object') {
          throw new TypeError('Expected the observer to be an object.')
        }

        function observeState() {
          if (observer.next) {
            observer.next(getState())
          }
        }

        observeState()
        const unsubscribe = outerSubscribe(observeState)
        return { unsubscribe }
      },

      [$$observable]() {
        return this
      }
    }
  }

  // 當一個store被創(chuàng)建的時候,會觸發(fā)dispatch來初始化state
  dispatch({ type: ActionTypes.INIT })

  return {
    dispatch,
    subscribe,
    getState,
    replaceReducer,
    [$$observable]: observable
  }
}

createStore所作的事情其實很簡單,主要的一個流程是,創(chuàng)建store,初始化state,返回一系列的方法,每個方法具體干了哪些事情,在上面的代碼中都已經(jīng)注釋好了.其中有一些其他的波折的東西,我們一會會介紹

applyMiddleware
import compose from './compose'

/**
 *這個方法就是將一系列的中間件作為參數(shù),將返回的函數(shù)作為createStore的第二個參數(shù)調(diào)用,最終結(jié)果
 *仍然會返回store提供的各個方法組成的對象,只是其中的dispatch方法是各個中間件組合成的一個組合
 * 函數(shù),使得在調(diào)用dispatch的時候會經(jīng)過各個中間件
 */
export default function applyMiddleware(...middlewares) {
  return (createStore) => (reducer, preloadedState, enhancer) => {
    const store = createStore(reducer, preloadedState, enhancer)
    let dispatch = store.dispatch
    let chain = []
// 使用store提供的getState方法和dispatch方法供各個中間件使用
    const middlewareAPI = {
      getState: store.getState,
      dispatch: (action) => dispatch(action)
    }
// 將所有的中間件中傳入store實例提供的getState和dispatch方法,返回值為函數(shù),通過compose方法整合出組合函數(shù)
    chain = middlewares.map(middleware => middleware(middlewareAPI))
    dispatch = compose(...chain)(store.dispatch)

    return {
      ...store,
      dispatch
    }
  }
}

applyMiddleware的方法主要是通過compose將各個中間件整合成一個組合函數(shù),通過將store.dispatch傳入函數(shù)中進行層層過濾,最終返回一個store

compose
/**
 * 從右到左整合成組合函數(shù)
 */

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)))
}

combineReducers
export default function combineReducers(reducers) {
  const reducerKeys = Object.keys(reducers)
  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]
    }
  }
  const finalReducerKeys = Object.keys(finalReducers)

  let unexpectedKeyCache
  if (process.env.NODE_ENV !== 'production') {
    unexpectedKeyCache = {}
  }

  let shapeAssertionError
  try {
    assertReducerShape(finalReducers)
  } catch (e) {
    shapeAssertionError = e
  }
// 最終返回的一個reducer,此函數(shù)在createStore的調(diào)用過程中,會將各個reducer的state組合成一個
//完整的state
  return function combination(state = {}, action) {
    if (shapeAssertionError) {
      throw shapeAssertionError
    }

    if (process.env.NODE_ENV !== 'production') {
      const warningMessage = getUnexpectedStateShapeWarningMessage(state, finalReducers, action, unexpectedKeyCache)
      if (warningMessage) {
        warning(warningMessage)
      }
    }

    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
  }

以上代碼的作用就是將多個拆分好的reducer最終組合成一個完整的reducer,其中store的key對應每一個state的key

bindActionCreators
function bindActionCreator(actionCreator, dispatch) {
  return (...args) => dispatch(actionCreator(...args))
}

/**
 */
export default function bindActionCreators(actionCreators, dispatch) {
  if (typeof actionCreators === 'function') {
    return bindActionCreator(actionCreators, dispatch)
  }

  if (typeof actionCreators !== 'object' || actionCreators === null) {
    throw new Error(
      `bindActionCreators expected an object or a function, instead received ${actionCreators === null ? 'null' : typeof actionCreators}. ` +
      `Did you write "import ActionCreators from" instead of "import * as ActionCreators from"?`
    )
  }

  const keys = Object.keys(actionCreators)
  const boundActionCreators = {}
  for (let i = 0; i < keys.length; i++) {
    const key = keys[i]
    const actionCreator = actionCreators[key]
    if (typeof actionCreator === 'function') {
      boundActionCreators[key] = bindActionCreator(actionCreator, dispatch)
    }
  }
  return boundActionCreators
}

以上代碼的主要作用就是將action創(chuàng)建函數(shù)和之前創(chuàng)造的store所得到的dispatch方法傳入,返回一個action綁定函數(shù),調(diào)用這個綁定函數(shù)會自動dispatch利用actionCreate所創(chuàng)建的action

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容