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