Redux createStore源碼學習

Redux API 和 Redux 源碼結構

Redux API

export {
    createStore,             //建立一個state用來存儲狀態樹
    combineReducers,   //合併reducer
    bindActionCreators,  //將dispatch和action結合
    applyMiddleware,     //調度中間件來加強store,例如中間件redux-thunk等
    compose              //從右向左組合多個函數, compose(f, g, h)會返回(...args) => f(g(h(...args)))
}

源碼結構

Redux源碼結構和提供的API大致對應,以下:
utils——warning.js //console中打印warning信息要用到的
applyMiddleware.js
bindActionCreators.js
combineReducers.js
compose.js
createStore.js
index.js //export 上述定義的moduleredux

createStore

上面咱們看到了redux的API和源碼結構,看的出來,warning.js和index.js不用解析,都看得懂,關鍵時其他的幾個module,那咱們從最重要的createStore講起。數組

export var ActionTypes = {
        INIT: '@@redux/INIT'
    }
   //首先定義了一個action類型,咱們知道更新state的惟一方法就是dispatch一個action,這個action是用
   // 來初始化state的,後面會用到它

如今來看下createStore的大致結構app

//接收三個參數
//reducer爲function。當dispatch一個action時,此函數接收action來更新state
//preloadState初始化State
//enhancer 爲function。用來加強store, Redux 定義有applyMiddleware來加強store,後面會
//單獨講applyMiddleware

export default function createStore(reducer, preloadedState, enhancer) {
    if (typeof preloadedState === 'function' && typeof enhancer === '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.')
        }
        //若是enhancer存在且爲函數,那麼則返回以下調用,若是enhancer爲applyMiddleware,那麼調用則
        //是applyMiddleware(middleware1, middleware2, middleware3...)(createStore)(reducer, preloadedState)。後面講applyMiddleware再詳細講。
        return enhancer(createStore)(reducer, preloadedState)
    }

    if (typeof reducer !== 'function') {
        //校驗reducer是否爲函數
        throw new Error('Expected the reducer to be a function.')
    }

    var currentReducer = reducer
    //獲得reducer

    var currentState = preloadedState
    //獲得初始init,沒有傳遞則爲undefined

    var currentListeners = []
    //定義一個數組用來存放listeners。就是一個函數數組,當state發生改變時,會循環執行這個數組裏面的函數

    var nextListeners = currentListeners
    //用來存儲下一次的listeners數組。爲何要有這個listeners數組呢?由於當state發生改變時,咱們根據
    //上面的currentListeners來循環執行函數,可是在這執行這些函數時,函數內部可能取消或者添加訂閱
    //(state改變時,添加或者取消執行函數),這時若是直接操做currentListeners ,至關於在循環
    //內部修改循環條件,執行瞬間就亂套了,有沒有啊,有沒有

    var isDispatching = false
    //reducer函數是否正在執行的標識

    function ensureCanMutateNextListeners() {
        //拷貝currentListeners一份爲nextListeners,這樣nextListeners的改變不會引發currentListeners的改變
        //(上面解釋過緣由啦)
    }

    function dispatch() {
        //觸發action去執行reducer,更新state
        .....
    }

    function subscribe() {
        //接收一個函數參數,訂閱state的改變。當state改變時會執行這個函數
        ....
    }

    function getState() {
        //獲取state樹
        ....
    }

    function replaceReducer() {
        //替換reducer
        ....
    }

    function observable() {
        //沒用,不解釋(後面有解釋)
        ......
    }


    dispatch({ type: ActionTypes.INIT })
    //執行dispatch函數,初始化state

    return {
        //真正的返回,執行createStore其實返回的就是這些東東
        dispatch,       //觸發action去執行reducer,更新state
        subscribe,     //訂閱state改變,state改變時會執行subscribe的參數(本身定義的一個函數)
        getState,      //獲取state樹
        replaceReducer,       //替換reducer
        [$$observable]: observable         
        //redux內部用的,對咱們來講沒用(非要深究它寫這是幹嗎的?咋跟
        //我同樣死腦筋呢,都說了沒用啦。算了,仍是告訴你把,就是內部用的,在測試代碼中會用到,感興
        //趣的能夠去test目錄下查看)
    }
}

如今是否是感受明朗(懵逼)了許多,懵逼就對了,接下來咱們再來解析一下dispatch, subscribe等函數的具體實現,或許會讓你明朗(更懵逼)起來
看了上面的大致結構,咱們明白如下這些就夠了。
createStore是一個函數,它定義了一些變量(currentState, currentListeners等)及函數(dispatch, subscribe等),而且調用了dispatch,最後返回一個對象,該對象包含的就是dispatch和subscribe等函數。接下來咱們來解析這些函數。
createStore裏面只調用了一個函數,那就是dispatch,那咱們就從這裏開始講起。異步

dispatch

它是這樣被調用的,有沒有很熟悉。。。async

dispatch({ type: ActionTypes.INIT })

來看看dispatch的源碼函數

function dispatch(action) {
    //校驗action參數,必須爲一個純粹的對象。這也說明了,咱們不能直接在redux作異步請求,而是須要
    //使用applyMiddleware去應用一些中間件。好比redux-thunk等
    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?'
      )
    }
    //判斷是否正在執行reducers函數,若是正在執行,此action不會觸發,那有人就問題了,那是否是我
    //的dispatch不會起做用,致使state沒有更新,數據是錯誤的? 答案是state是不會有錯。由於redux本
    //身整個更新state的過程是同步的,從dipatch——>reducers——>state。因此這段代碼意在你定義的
    //reducers函數中不容許調用dispatch
    if (isDispatching) {
      throw new Error('Reducers may not dispatch actions.')
    }

    try {
      //設置標識爲true,而且執行currentReducer,還記得嗎?這個咱們經過參數獲取到的一個函數,每每是我
      //們調用combineReducers返回,combineReducers咱們後面解析
      isDispatching = true
      //調用reducers函數
      currentState = currentReducer(currentState, action)
    } finally {
      isDispatching = false
    }
    //調用全部訂閱state改變的函數,這些函數就能夠經過getState函數獲取到最新的state值。訂閱的函數
    //從哪裏來呢,從subscribe中來, 咱們後面來解析subscribe和getState
    var listeners = currentListeners = nextListeners
    for (var i = 0; i < listeners.length; i++) {
      listeners[i]()
    }

    return action
  }
相關文章
相關標籤/搜索