摘要:定義了幾個函數用于修改上面的幾個局部變量主要包括函數用于獲取用于替換用于修改列表用于觸發執行,生成新的,并且,執行列表中的每一個函數完整解析請參考我的,如果對您有幫助,歡迎,有任何問題也請指正。
歡迎關注redux源碼分析系列文章:
redux源碼分析之一:createStore.js
redux源碼分析之二:combineReducers.js
redux源碼分析之三:bindActionCreators.js
redux源碼分析之四:compose.js
redux源碼分析之五:applyMiddleware
createStore.js是redux的核心文件,暴露了一個函數createStore,函數執行后返回一個對象,該對象包含了4個關鍵的方法:dispatch, subscribe, getState, replaceReducer,代碼如下。
export default function createStore(reducer, preloadedState, enhancer) { //中間代碼略 return { dispatch, subscribe, getState, replaceReducer, [$$observable]: observable } }一、createStore函數的參數:
reducer:reducer是一個函數,該函數會返回一個全新的state,而state則保存了所有的數據
preloadedState:初始state
enhancer:這個參數特別有意思,如果該enhancer參數存在的話,會將當前的createStore函數作為參數傳入enhancer函數,并且,enhancer執行之后得到一個新函數,該新函數其實就是一個加強版的createStore函數,新的函數會把之前的reducer和preloadeState作為參數傳入并執行。這個enhancer參數為redux中間件提供了入口。
二、參數檢查代碼及異常處理://如果preloadedState沒有傳,但是enhancer參數傳了,重置一下變量 if (typeof preloadedState === "function" && typeof enhancer === "undefined") { enhancer = preloadedState preloadedState = undefined } //如果enhancer傳了,但是不是函數,則報錯提示,否則執行enhancer函數, //并繼續執行enhancer函數返回的加強版的createStore函數, //參數reducer以及preloadeState和原createStore函數保持一致 if (typeof enhancer !== "undefined") { if (typeof enhancer !== "function") { throw new Error("Expected the enhancer to be a function.") } return enhancer(createStore)(reducer, preloadedState) } //如果reducer不是函數,則報錯 if (typeof reducer !== "function") { throw new Error("Expected the reducer to be a function.") }三、定義的幾個局部變量:
let currentReducer = reducer //保存了當前的reducer函數,該reducer函數可以被動態替換掉 let currentState = preloadedState //保存了當前的state數據 let currentListeners = [] //保存了當前注冊的函數列表 let nextListeners = currentListeners let isDispatching = false //是否正在dispatch一個action
最關鍵的是currentState變量,調用createStore之后,currentState變量保存了當前狀態的所有數據
四、定義了幾個函數://確保nextListeners和currentListeners不是同一個引用 function ensureCanMutateNextListeners() { if (nextListeners === currentListeners) { //如果是同一個引用,則淺拷貝currentListeners到nextListeners nextListeners = currentListeners.slice() } }
//getState函數,返回局部變量currentState,以獲取當前狀態 function getState() { return currentState }
//注冊一個函數,將注冊函數放入局部變量nextListeners數組里面 //注冊函數的返回值是一個注銷函數,注銷函數執行可以將剛剛添加進nextListeners的listener函數又刪除掉。這里很有意思,外部必須在調用subscribe執行現場保存好unsubscribe函數,否則將無法注銷一個函數 function subscribe(listener) { //如果listener不是函數,直接報錯 if (typeof listener !== "function") { throw new Error("Expected listener to be a function.") } let isSubscribed = true //確保nextListeners不是currentListeners,以保證修改的是nextListeners,而不是currentListeners ensureCanMutateNextListeners() //將監聽函數放入監聽函數列表尾部 nextListeners.push(listener) //返回一個函數,該函數可以從監聽函數列表中刪除剛剛注冊的監聽函數 return function unsubscribe() { if (!isSubscribed) { return } isSubscribed = false ensureCanMutateNextListeners() const index = nextListeners.indexOf(listener) nextListeners.splice(index, 1) } }
//觸發action的函數:每次觸發一個action,currentListeners中的所有函數都要執行一遍 function dispatch(action) { //如果action不是普通的對象,直接報錯 if (!isPlainObject(action)) { throw new Error( "Actions must be plain objects. " + "Use custom middleware for async actions." ) } //如果action沒有type屬性,直接報錯:說明action對象必須要包含type字段 if (typeof action.type === "undefined") { throw new Error( "Actions may not have an undefined "type" property. " + "Have you misspelled a constant?" ) } //如果當前正在觸發另外一個action,直接報錯 if (isDispatching) { throw new Error("Reducers may not dispatch actions.") } try { //先將標志位置為true isDispatching = true //執行傳入的reducer函數,該函數返回一個新的state對象,并賦值給currentState變量 currentState = currentReducer(currentState, action) } finally { //reducer函數執行完成后,將isDispatching恢復成false,方便下次action的觸發 isDispatching = false } //每一次觸發一個action,所有的監聽函數都要全部重新執行一遍, //并且把上次得到的新的監聽函數列表賦值成為當前的監聽函數列表。這是一個懶操作,并不是在subscribe的時候就操作了,而是在dispatch的時候才操作 const listeners = currentListeners = nextListeners for (let i = 0; i < listeners.length; i++) { const listener = listeners[i] listener() } //該dispatch函數的返回值是原來的action return action }
//替換reducer函數:這個函數允許運行時動態替換最開始調用createStore函數時傳入的reducer,并且替換掉reducer之后,重新dispatch一個action,得到全新的currentState對象 function replaceReducer(nextReducer) { //如果nextReducer不是函數,直接報錯 if (typeof nextReducer !== "function") { throw new Error("Expected the nextReducer to be a function.") } //把新的reducer賦值給當前的currentReducer變量,得到一個全新的currentReducer currentReducer = nextReducer // 觸發一個初始action: // 1.這樣就可以完成一次監聽函數列表的全部調用 // 2.可以得到一個全新的currentState; dispatch({type: ActionTypes.INIT}) }
function observable() { const outerSubscribe = subscribe return { /** * The minimal observable subscription method. * @param {Object} observer Any object that can be used as an observer. * The observer object should have a `next` method. * @returns {subscription} An object with an `unsubscribe` method that can * be used to unsubscribe the observable from the store, and prevent further * emission of values from the observable. */ 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 } } }五、初始化:
初始化很簡單,一句代碼,直接調用一次dispatch,就會執行所有的注冊函數,并且執行reducer函數,生成初始化的state
//馬上內部調用一次初始化的操作,根據傳入的reducer函數,preloadedState生成一個全新的currentState和全新的reducer dispatch({type: ActionTypes.INIT})
總結一下就是:
createStore函數定義了幾個局部變量用于記錄狀態,主要包括currentState記錄數據狀態,currentListeners記錄注冊函數列表,currentReducer記錄當前的reducer函數。
定義了幾個函數用于修改上面的幾個局部變量:主要包括getState函數用于獲取currentState;replaceReducer用于替換currentReducer;subscribe用于修改currentListeners列表;dispatch用于觸發currentReducer執行,生成新的currentState,并且,執行currentListeners列表中的每一個函數;
完整解析請參考我的github:https://github.com/abczhijia/...,如果對您有幫助,歡迎star,有任何問題也請指正。
(完)
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/88897.html
摘要:進階教程原文保持更新寫在前面相信您已經看過簡明教程,本教程是簡明教程的實戰化版本,伴隨源碼分析用的是編寫,看到有疑惑的地方的,可以復制粘貼到這里在線編譯總覽在的源碼目錄,我們可以看到如下文件結構打醬油的,負責在控制臺顯示警告信息入口文件除去 Redux 進階教程 原文(保持更新):https://github.com/kenberkele... 寫在前面 相信您已經看過 Redux ...
摘要:接下來筆者就從源碼中探尋是如何實現的。其實很簡單,可以簡單理解為一個約束了特定規則并且包括了一些特殊概念的的發布訂閱器。新舊中存在的任何都將收到先前的狀態。這有效地使用來自舊狀態樹的任何相關數據填充新狀態樹。 Redux是當今比較流行的狀態管理庫,它不依賴于任何的框架,并且配合著react-redux的使用,Redux在很多公司的React項目中起到了舉足輕重的作用。接下來筆者就從源碼...
摘要:訂閱器不應該關注所有的變化,在訂閱器被調用之前,往往由于嵌套的導致發生多次的改變,我們應該保證所有的監聽都注冊在之前。 前言 用 React + Redux 已經一段時間了,記得剛開始用Redux 的時候感覺非常繞,總搞不起里面的關系,如果大家用一段時間Redux又看了它的源碼話,對你的理解會有很大的幫助。看完后,在回來看Redux,有一種 柳暗花明又一村 的感覺 ,. 源碼 我分析的...
摘要:到月底了,小明的爸爸的單位發了工資總計塊大洋,拿到工資之后第一件的事情就是上交,毫無疑問的,除非小明爸爸不要命了。當小明的爸爸收到這個通知之后,心的一塊大石頭也就放下來了。下面我們正式開始我們的源碼閱讀之旅。 前言 用過react的小伙伴對redux其實并不陌生,基本大多數的React應用用到它。一般大家用redux的時候基本都不會單獨去使用它,而是配合react-redux一起去使用...
摘要:否則的話,認為只是一個普通的,將通過也就是進一步分發。在本組件內的應用傳遞給子組件源碼解析期待一個作為傳入,里面是如果只是傳入一個,則通過返回被綁定到的函數遍歷并通過分發綁定至將其聲明為的屬性之一接收的作為傳入。 原文鏈接:https://github.com/ecmadao/Co...轉載請注明出處 本文不涉及redux的使用方法,因此可能更適合使用過redux的玩家翻閱? 預熱...
閱讀 3491·2021-11-18 10:07
閱讀 1589·2021-11-04 16:08
閱讀 1513·2021-11-02 14:43
閱讀 1088·2021-10-09 09:59
閱讀 844·2021-09-08 10:43
閱讀 1079·2021-09-07 09:59
閱讀 963·2019-12-27 11:56
閱讀 1012·2019-08-30 15:56