Redux源碼學(xué)習(xí)

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

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

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

從以上代碼可以看出來(lái),就是Redux提供的API

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

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

/**
 * 此函數(shù)接受三個(gè)參數(shù),第一個(gè)參數(shù)是一個(gè)函數(shù),就是我們的reduce函數(shù),返回一個(gè)state
 */
export default function createStore(reducer, preloadedState, enhancer) {
  /**當(dāng)preloadedState為函數(shù)且enhancer不存在時(shí),將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提供的一些方法,如此處最后返回對(duì)象,只是其中的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()
    }
  }

  /**
   * 讀取當(dāng)前整個(gè)狀態(tài)樹(shù)
   */
  function getState() {
    return currentState
  }

  /**
   * dispatch訂閱方法,當(dāng)調(diào)用此方法時(shí)會(huì)在事件監(jiān)聽(tīng)器中加入監(jiān)聽(tīng)函數(shù),當(dāng)dispatch了一個(gè)action時(shí),所有訂  
 *閱的方法都會(huì)執(zhí)行,此方法執(zhí)行完成會(huì)返回一個(gè)取消訂閱方法,用于取消訂閱事件
   */
  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ù)接受一個(gè)為對(duì)象的參數(shù),其中必須包含一個(gè)type屬性,會(huì)將新的state賦值給currentState,并且會(huì)執(zhí)行所有subscribe過(guò)的函數(shù),并返回當(dāng)前的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.')
    }
    /** 改變當(dāng)前dispatching狀態(tài)為true,并且將更改后的state賦值給當(dāng)前state
    */
    try {
      isDispatching = true
      currentState = currentReducer(currentState, action)
    } finally {
      isDispatching = false
    }
  // 當(dāng)觸發(fā)dispatching函數(shù)時(shí),所有訂閱的函數(shù)都會(huì)被觸發(fā)
    const listeners = currentListeners = nextListeners
    for (let i = 0; i < listeners.length; i++) {
      const listener = listeners[i]
      listener()
    }

    return action
  }

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

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

  /**
   *不直接提供給開(kāi)發(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
      }
    }
  }

  // 當(dāng)一個(gè)store被創(chuàng)建的時(shí)候,會(huì)觸發(fā)dispatch來(lái)初始化state
  dispatch({ type: ActionTypes.INIT })

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

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

applyMiddleware
import compose from './compose'

/**
 *這個(gè)方法就是將一系列的中間件作為參數(shù),將返回的函數(shù)作為createStore的第二個(gè)參數(shù)調(diào)用,最終結(jié)果
 *仍然會(huì)返回store提供的各個(gè)方法組成的對(duì)象,只是其中的dispatch方法是各個(gè)中間件組合成的一個(gè)組合
 * 函數(shù),使得在調(diào)用dispatch的時(shí)候會(huì)經(jīng)過(guò)各個(gè)中間件
 */
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方法供各個(gè)中間件使用
    const middlewareAPI = {
      getState: store.getState,
      dispatch: (action) => dispatch(action)
    }
// 將所有的中間件中傳入store實(shí)例提供的getState和dispatch方法,返回值為函數(shù),通過(guò)compose方法整合出組合函數(shù)
    chain = middlewares.map(middleware => middleware(middlewareAPI))
    dispatch = compose(...chain)(store.dispatch)

    return {
      ...store,
      dispatch
    }
  }
}

applyMiddleware的方法主要是通過(guò)compose將各個(gè)中間件整合成一個(gè)組合函數(shù),通過(guò)將store.dispatch傳入函數(shù)中進(jìn)行層層過(guò)濾,最終返回一個(gè)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
  }
// 最終返回的一個(gè)reducer,此函數(shù)在createStore的調(diào)用過(guò)程中,會(huì)將各個(gè)reducer的state組合成一個(gè)
//完整的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
  }

以上代碼的作用就是將多個(gè)拆分好的reducer最終組合成一個(gè)完整的reducer,其中store的key對(duì)應(yīng)每一個(gè)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方法傳入,返回一個(gè)action綁定函數(shù),調(diào)用這個(gè)綁定函數(shù)會(huì)自動(dòng)dispatch利用actionCreate所創(chuàng)建的action

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 前言 本文 有配套視頻,可以酌情觀看。 文中內(nèi)容因各人理解不同,可能會(huì)有所偏差,歡迎朋友們聯(lián)系我討論。 文中所有內(nèi)...
    珍此良辰閱讀 11,942評(píng)論 23 111
  • http://gaearon.github.io/redux/index.html ,文檔在 http://rac...
    jacobbubu閱讀 80,058評(píng)論 35 198
  • 看到這篇文章build an image gallery using redux saga,覺(jué)得寫的不錯(cuò),長(zhǎng)短也適...
    smartphp閱讀 6,214評(píng)論 1 29
  • 一、什么情況需要redux? 1、用戶的使用方式復(fù)雜 2、不同身份的用戶有不同的使用方式(比如普通用戶和管...
    初晨的筆記閱讀 2,064評(píng)論 0 11
  • 學(xué)習(xí)必備要點(diǎn): 首先弄明白,Redux在使用React開(kāi)發(fā)應(yīng)用時(shí),起到什么作用——狀態(tài)集中管理 弄清楚Redux是...
    賀賀v5閱讀 8,953評(píng)論 10 58