摘要:核心源碼解析本文默認,你已經(jīng)有了一定的基礎(chǔ)。定義如何更新初始狀態(tài)是讓中間件按照規(guī)定模型洋蔥模型回形針模型執(zhí)行的函數(shù),就是下文將會介紹的函數(shù)的返回值返回中的。洋蔥模型回形針模型調(diào)用后的結(jié)果對上面的代碼換一種展現(xiàn)方式中間件要執(zhí)行,先得執(zhí)行。
redux 核心源碼解析
本文默認,你已經(jīng)有了一定的es6基礎(chǔ)。源碼有刪減,對其中的核心邏輯做解釋
redux 是 一個用 javascript 管理數(shù)據(jù)的容器,這個容器的狀態(tài)是可以預(yù)測的。
redux 可以跟任何是個 視圖(view)層的框架結(jié)合使用
開發(fā)react應(yīng)用,經(jīng)常結(jié)合使用 redux
redux 比較抽象,核心旨在定義一個數(shù)據(jù)讀寫的規(guī)范,和數(shù)據(jù)變化后的回調(diào)接口
三大原則單一數(shù)據(jù)源 :整個應(yīng)用的 state 被儲存在一棵 object tree 中,并且這個 object tree 只存在于唯一一個 store 中。
State 是只讀的:惟一改變 state 的方法就是觸發(fā) action,action 是一個用于描述已發(fā)生事件的普通對象。
使用純函數(shù)來執(zhí)行修改 :為了描述 action 如何改變 state tree ,你需要編寫 reducers。純函數(shù):http://web.jobbole.com/86136/
createStore.js 核心邏輯function createStore(reducer, preloadedState, enhancer) { /* 參數(shù)格式/類型 匹配。 reducer:定義 state 如何更新 preloadedState: 初始狀態(tài) enhancer 是讓中間件按照規(guī)定模型(洋蔥模型/回形針模型)執(zhí)行的函數(shù),就是下文將會介紹的 applyMiddleware函數(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.") } return enhancer(createStore)(reducer, preloadedState) } let currentReducer = reducer let currentState = preloadedState let currentListeners = [] let nextListeners = currentListeners /** * 返回 store 中的 state。 * State 是只讀的:這個 state 是 createStore 函數(shù)內(nèi)部變量,只能通過 createStore 提供的 getState 方法讀取 state。 */ function getState() { return currentState } /** * listener 是函數(shù),維護在內(nèi)部變量 nextListeners(數(shù)組) 中 * 調(diào)用 subscribe(訂閱) 方法,添加 listener 在數(shù)組中 * 并返回一個方法,可以把當前添加在數(shù)組中的 listener 函數(shù)取出。 * * listener 的作用:當 state 發(fā)生變化的時候,listener具體去做些事情,比如更新 UI。 * 只定義做事情的時機,具體做什么由調(diào)用者自己實現(xiàn) */ function subscribe(listener) { nextListeners.push(listener) return function unsubscribe() { const index = nextListeners.indexOf(listener) nextListeners.splice(index, 1) } } /** * dispatch的作用:更改 state * 更改的方式:根據(jù)傳入的 reducer 和 action,產(chǎn)生一個新的 state。 * * action的要求:是一個純粹的對象字面量,并且具有 type 字段 * 經(jīng)過 reducer 根據(jù) action 把 當前 state 更新。一旦更新結(jié)束,立即把數(shù)組中的每一個 listener 調(diào)用一遍 */ 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?" ) } currentState = currentReducer(currentState, action) const listeners = (currentListeners = nextListeners) for (let i = 0; i < listeners.length; i++) { const listener = listeners[i] listener() } return action } /** * 可以更改 reducer * reducer 一旦更改,立即 dispatch 一次,把 state 更新,把注冊的 listener 執(zhí)行一遍 */ function replaceReducer(nextReducer) { if (typeof nextReducer !== "function") { throw new Error("Expected the nextReducer to be a function.") } currentReducer = nextReducer dispatch({ type: ActionTypes.REPLACE }) } /** * 一旦 調(diào)用 createStore 函數(shù),立即 dispatch 一遍,把 state 更新,把注冊的 listener 執(zhí)行一遍 */ dispatch({ type: ActionTypes.INIT }) return { dispatch, subscribe, getState, replaceReducer, } }redux 中的中間件
redux 中的中間件一個典型的應(yīng)用場景是處理異步接口返回數(shù)據(jù)
常見的 web 系統(tǒng)中的中間件,不侵入業(yè)務(wù)邏輯,功能優(yōu)盤化,即用即插。
middleWareA(middleWareB(middleWareC("hello world"))); /** * 調(diào)用后的結(jié)果: * hello world form middleWareC;form middleWareB;form middleWareA; * */ function middleWareA(string){ return `${string} form middleWareA;`; }; function middleWareB(string){ return `${string} form middleWareB;`; }; function middleWareC(string){ return `${string} form middleWareC;`; };
對上面的代碼換一種展現(xiàn)方式
middleWareA( middleWareB( middleWareC("hello world") ) );
中間件 middleWareA 要執(zhí)行,先得執(zhí)行 middleWareB。中間件 middleWareB 要執(zhí)行,先得執(zhí)行 middleWareC,數(shù)據(jù)層層傳遞
調(diào)用順序為: A-->B-->C
執(zhí)行結(jié)束的順序為:C-->B-->A
這就是 洋蔥模型 或者 回形針模型
下面看一個 redux-thunk 中間件
function createThunkMiddleware() { /** * dispatch 是基于 store.dispatch,且層層經(jīng)過中間件包裝后的方法 * getState 是 createStore 函數(shù)執(zhí)行后導(dǎo)出的方法; * next 為下一個中間件 * action 的預(yù)期格式為 createStore 中設(shè)計的 action的格式,是一個字面量對象。在這里做action類型的判斷 */ return ({ dispatch, getState }) => next => action => { // 如果 action 是函數(shù) if (typeof action === "function") { return action(dispatch, getState); } // 如果不是函數(shù),流轉(zhuǎn)到下一個中間件,期待最后的一個中間件的 action 是一個預(yù)期模式的 action return next(action); }; } export default createThunkMiddleware();applyMiddleware 核心邏輯
/** * middlewares 是包含中間件的數(shù)組 * 需要的中間件,依次傳入。如: applyMiddleware(middlewaresA, middlewaresB, middlewaresC) * applyMiddleware 執(zhí)行后的返回的函數(shù)就是一個 enhancer */ export default function applyMiddleware(...middlewares) { return createStore => (...args) => { // args解構(gòu)后,就是 reducer, preloadedState // 這里的 store 就是 createStore 函數(shù)生產(chǎn)的全局的狀態(tài)樹,參見上文對 createStore 的解釋 const store = createStore(...args) let dispatch = () => { }; let chain = [] /** * 每個中間件中需要傳遞的數(shù)據(jù) */ const middlewareAPI = { getState: store.getState,// 獲取 state 的函數(shù),用于讀 dispatch: (...args) => dispatch(...args)// 更新 state 的函數(shù),用于寫。 } // 遍歷中間件 chain = middlewares.map(middleware => middleware(middlewareAPI)) // 下面的代碼的效果,就是要運用洋蔥模型/回形針模型:middlewareA(middlewareB(middlewareC(store.dispatch))) // 關(guān)于 compose 比較簡單:https://github.com/reactjs/redux/blob/master/src/compose.js // 中間件的開始是 原生的store.dispatch,結(jié)束時是 一個攜帶了各種中間件信息的 dispatch dispatch = compose(...chain)(store.dispatch) /** * 尤其注意這里的 dispatch * 開始時定義了一個空的 dispatch 函數(shù),是為了給 middlewareAPI 的 dispatch 一個初始值 * 實際上真正的 dispatch 是中間件根據(jù)原生的 store.dispatch 按照洋蔥模型/回形針模型,執(zhí)行了一邊,調(diào)用所有中間件后的 dispatch * 這個 dispatch 攜帶了傳入的每一個中間件的操作。一次如果此時傳入 action 更新 state,所有的中間件都會被執(zhí)行一遍。 */ return { ...store, dispatch } } }
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/92645.html
摘要:此篇文章可作為源碼導(dǎo)讀使用,只說明了其中部分核心代碼,并進行了一些簡化處理用法回顧用來創(chuàng)建創(chuàng)建在中編寫純函數(shù)來處理用通過和來操作里的數(shù)據(jù)用來監(jiān)聽中的數(shù)據(jù)是否發(fā)生了變化用來獲取中的,并更新視圖核心代碼初始化數(shù)據(jù)存放,是傳入的默認值存放傳入的創(chuàng) 此篇文章可作為redux源碼導(dǎo)讀使用,只說明了其中部分核心代碼,并進行了一些簡化處理 用法回顧 用createStore來創(chuàng)建store 創(chuàng)建A...
摘要:源碼解析模塊的代碼十分簡練,但是實現(xiàn)的作用卻是十分強大。只傳遞一個參數(shù)的時候,就直接把這個函數(shù)返回返回組合函數(shù)這就是對源碼的一個整體解讀,水平有限,歡迎拍磚。后續(xù)的源碼解讀和測試例子可以關(guān)注源碼解讀倉庫 compose源碼解析 compose模塊的代碼十分簡練,但是實現(xiàn)的作用卻是十分強大。redux為何稱為redux?有人說就是reduce和flux的結(jié)合體,而reduce正是comp...
摘要:源碼解析是最核心的模塊。比如,當我們需要使用中間件的時候,就會像第三個參數(shù)傳遞一個返回值是一個。后續(xù)的源碼解讀和測試例子可以關(guān)注源碼解讀倉庫 createStore源碼解析 createStore是redux最核心的模塊。這個模塊就是用于創(chuàng)建一個store對象,同時,對外暴露出dispatch,getState,subscribe和replaceReducer方法。(源碼中關(guān)于obse...
摘要:然后循環(huán)調(diào)用中的更新函數(shù),更新函數(shù)一般是我們的渲染函數(shù),函數(shù)內(nèi)部會調(diào)用來獲取數(shù)據(jù),所以頁面會更新。 歡迎訪問個人網(wǎng)站:https://www.neroht.com/ 前言 前幾天寫了一篇react另一個狀態(tài)管理工具Unstated的源碼解析。開啟了我的看源碼之路。想一想用了好長時間的redux,但從沒有深究過原理,遇到報錯更是懵逼,所以就啃了一遍它的源碼,寫了這篇文章,分享我對于它的理...
摘要:然后循環(huán)調(diào)用中的更新函數(shù),更新函數(shù)一般是我們的渲染函數(shù),函數(shù)內(nèi)部會調(diào)用來獲取數(shù)據(jù),所以頁面會更新。前言 前幾天寫了一篇react另一個狀態(tài)管理工具Unstated的源碼解析。 開啟了我的看源碼之路。想一想用了好長時間的redux,但從沒有深究過原理,遇到報錯更是懵逼,所以就啃了一遍它的源碼,寫了這篇文章, 分享我對于它的理解。 API概覽 看一下redux源碼的index.js,看到了我們最...
閱讀 2949·2021-11-23 09:51
閱讀 1666·2021-10-15 09:39
閱讀 1056·2021-08-03 14:03
閱讀 2880·2019-08-30 15:53
閱讀 3437·2019-08-30 15:52
閱讀 2487·2019-08-29 16:17
閱讀 2788·2019-08-29 16:12
閱讀 1647·2019-08-29 15:26