createStore原理及作用

createStore創(chuàng)建一個(gè) Redux store 來(lái)以存放應(yīng)用中所有的 state,應(yīng)用中應(yīng)有且僅有一個(gè) store。其中暴露 dispatch, subscribe, getState, replaceReducer 方法。

createStore概念圖

源碼及分析

/**
 * 初始化時(shí),默認(rèn)傳遞的 action,默認(rèn)也應(yīng)該返回初始化的 state
 */
export var ActionTypes = {
  INIT: '@@redux/INIT'
}
/**
 * 創(chuàng)建 store, 參數(shù)根 reducer, state 以及中間件
 */
export default function createStore(reducer, preloadedState, enhancer) {
//判斷接受的參數(shù)個(gè)數(shù),來(lái)指定 reducer 、 preloadedState 和 enhancer
  if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') {
    enhancer = preloadedState
    preloadedState = undefined
  }
// 如果 enhancer 存在并且適合合法的函數(shù),那么調(diào)用 enhancer,并且終止當(dāng)前函數(shù)執(zhí)行
  if (typeof enhancer !== 'undefined') {
    if (typeof enhancer !== 'function') {
      throw new Error('Expected the enhancer to be a function.')
    }
    return enhancer(createStore)(reducer, preloadedState)
  }
  if (typeof reducer !== 'function') {
    throw new Error('Expected the reducer to be a function.')
  }
// 儲(chǔ)存當(dāng)前的 currentReducer
  var currentReducer = reducer
// 儲(chǔ)存當(dāng)前的狀態(tài)
  var currentState = preloadedState
 // 儲(chǔ)存當(dāng)前的監(jiān)聽(tīng)函數(shù)列表
  var currentListeners = []
// 儲(chǔ)存下一個(gè)監(jiān)聽(tīng)函數(shù)列表
  var nextListeners = currentListeners
  var isDispatching = false

  // 這個(gè)函數(shù)可以根據(jù)當(dāng)前監(jiān)聽(tīng)函數(shù)的列表生成新的下一個(gè)監(jiān)聽(tīng)函數(shù)列表引用
  function ensureCanMutateNextListeners() {
    if (nextListeners === currentListeners) {
      nextListeners = currentListeners.slice()
    }
  }
  
//這個(gè)函數(shù)可以獲取當(dāng)前的狀態(tài),createStore 中的 currentState 儲(chǔ)存當(dāng)前的狀態(tài)樹(shù),這是一個(gè)閉包
  function getState() {
    return currentState
  }

  // 訂閱事件,返回移除訂閱函數(shù),巧妙的利用了閉包
  function subscribe(listener) {
      // 判斷傳入的參數(shù)是否為函數(shù)
    if (typeof listener !== 'function') {
      throw new Error('Expected listener to be a function.')
    }
    var isSubscribed = true
    ensureCanMutateNextListeners()
    nextListeners.push(listener)
    return function unsubscribe() {
      if (!isSubscribed) {
        return
      }
      isSubscribed = false
      ensureCanMutateNextListeners()
      var index = nextListeners.indexOf(listener)
      nextListeners.splice(index, 1)
    }
  }
  // 執(zhí)行 reducer,并觸發(fā)訂閱事件
  function dispatch(action) {
    // https://lodash.com/docs#isPlainObject
    if (!isPlainObject(action)) {
      throw new Error(
        'Actions must be plain objects. ' +
        'Use custom middleware for async actions.'
      )
    }

     // 判斷 action 是否有 type{必須} 屬性
    if (typeof action.type === 'undefined') {
      throw new Error(
        'Actions may not have an undefined "type" property. ' +
        'Have you misspelled a constant?'
      )
    }

    // 如果正在 dispatch 則拋出錯(cuò)誤
    if (isDispatching) {
      throw new Error('Reducers may not dispatch actions.')
    }

    // 對(duì)拋出 error 的兼容,但是無(wú)論如何都會(huì)繼續(xù)執(zhí)行 isDispatching = false 的操作
    try {
      isDispatching = true
      // 產(chǎn)生新的 state
      currentState = currentReducer(currentState, action)
    } finally {
      isDispatching = false
    }
    // 觸發(fā)訂閱的事件
    var listeners = currentListeners = nextListeners
    for (var i = 0; i < listeners.length; i++) {
      listeners[i]()
    }
    return action
  }
  /**
   * 動(dòng)態(tài)替換 reducer
   */
  function replaceReducer(nextReducer) {
    if (typeof nextReducer !== 'function') {
      throw new Error('Expected the nextReducer to be a function.')
    }
    currentReducer = nextReducer
    dispatch({ type: ActionTypes.INIT })
  }
  dispatch({ type: ActionTypes.INIT })
  return {
    dispatch,
    subscribe,
    getState,
    replaceReducer
  }
}

首先定義了一個(gè) ActionTypes 對(duì)象,它是一個(gè) action,是一個(gè) Redux 的私有 action,不允許外界觸發(fā),用來(lái)初始化 Store 的狀態(tài)樹(shù)和改變 reducers 后初始化 Store 的狀態(tài)樹(shù)。

參數(shù)

它可以接受三個(gè)參數(shù),reducer、preloadedState、enhancer:

  • reducer:是一個(gè)函數(shù),返回下一個(gè)狀態(tài),接受兩個(gè)參數(shù):當(dāng)前狀態(tài) 和 觸發(fā)的 action;
  • preloadedState:初始狀態(tài)對(duì)象,可以很隨意指定,比如服務(wù)端渲染的初始狀態(tài),但是如果使用 combineReducers 來(lái)生成 reducer,那必須保持狀態(tài)對(duì)象的 key 和 combineReducers 中的 key 相對(duì)應(yīng);
  • enhancer:store 的增強(qiáng)器函數(shù),可以指定為 第三方的中間件,時(shí)間旅行,持久化 等等,但是這個(gè)函數(shù)只能用 Redux 提供的 applyMiddleware 函數(shù)來(lái)生成;
返回

調(diào)用完函數(shù)它返回的接口是 dispatch、subscribe、getStatere、placeReducer,這也是我們開(kāi)發(fā)中主要使用的幾個(gè)接口。

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

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

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

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