摘要:數(shù)組為新的數(shù)組,包含了方法將新的和結(jié)合起來(lái),生成一個(gè)新的方法返回的新增了一個(gè)方法,這個(gè)新的方法是改裝過(guò)的,也就是封裝了中間件的執(zhí)行。
3.3 理解 Redux 中間件書(shū)籍完整目錄
這一小節(jié)會(huì)講解 redux 中間件的原理,為下一節(jié)講解 redux 異步 action 做鋪墊,主要內(nèi)容為:
Redux 中間件是什么
使用 Redux 中間件
logger 中間件結(jié)構(gòu)分析
applyMiddleware
中間件的執(zhí)行過(guò)程
3.3.1 Redux 中間件是什么Redux moddleware provides a third-party extension point between dispatching an action, and the moment it reaches the reducer.
redux 提供了類似后端 Express 的中間件概念,本質(zhì)的目的是提供第三方插件的模式,自定義攔截
action -> reducer 的過(guò)程。變?yōu)?action -> middlewares -> reducer 。這種機(jī)制可以讓我們改變數(shù)據(jù)流,實(shí)現(xiàn)如異步 action ,action 過(guò)濾,日志輸出,異常報(bào)告等功能。
Redux 提供了一個(gè)叫 applyMiddleware 的方法,可以應(yīng)用多個(gè)中間件,以日志輸出中間件為例
import { createStore, applyMiddleware } from "redux" import createLogger from "redux-logger" import rootReducer from "./reducers" const loggerMiddleware = createLogger() const initialState = {} return createStore( rootReducer, initialState, applyMiddleware( loggerMiddleware ) )3.3.3 logger 中間件結(jié)構(gòu)分析
看看 redux-logger 的源碼結(jié)構(gòu)
function createLogger(options = {}) { /** * 傳入 applyMiddleWare 的函數(shù) * @param {Function} { getState }) [description] * @return {[type]} [description] */ return ({ getState }) => (next) => (action) => { let returnedValue; const logEntry = {}; logEntry.prevState = stateTransformer(getState()); logEntry.action = action; // .... returnedValue = next(action); // .... logEntry.nextState = stateTransformer(getState()); // .... return returnedValue; }; } export default createLogger;
Logger 中這樣的結(jié)構(gòu) ({ getState }) => (next) => (action) => {} 看起來(lái)是很奇怪的,這種設(shè)計(jì)如果沒(méi)有 es6 的箭頭函數(shù),擴(kuò)展下來(lái)就是
/** * getState 可以返回最新的應(yīng)用 store 數(shù)據(jù) */ function ({getState}) { /** * next 表示執(zhí)行后續(xù)的中間件,中間件有可能有多個(gè) */ return function (next) { /** * 中間件處理函數(shù),參數(shù)為當(dāng)前執(zhí)行的 action */ return function (action) {...} } }
這樣的結(jié)構(gòu)本質(zhì)上就是為了將 middleware 串聯(lián)起來(lái)執(zhí)行,為了分析 middleware 的執(zhí)行順序,還得看看 applyMiddleware 的實(shí)現(xiàn)
3.3.4 applyMiddleware 分析下面是 applyMiddleware 完整的代碼,參數(shù)為 middlewares 數(shù)組:
import compose from "./compose" /** * Creates a store enhancer that applies middleware to the dispatch method * of the Redux store. This is handy for a variety of tasks, such as expressing * asynchronous actions in a concise manner, or logging every action payload. * * See `redux-thunk` package as an example of the Redux middleware. * * Because middleware is potentially asynchronous, this should be the first * store enhancer in the composition chain. * * Note that each middleware will be given the `dispatch` and `getState` functions * as named arguments. * * @param {...Function} middlewares The middleware chain to be applied. * @returns {Function} A store enhancer applying the middleware. */ export default function applyMiddleware(...middlewares) { return (createStore) => (reducer, preloadedState, enhancer) => { var store = createStore(reducer, preloadedState, enhancer) var dispatch = store.dispatch var chain = [] var middlewareAPI = { getState: store.getState, dispatch: (action) => dispatch(action) } chain = middlewares.map(middleware => middleware(middlewareAPI)) dispatch = compose(...chain)(store.dispatch) return { ...store, dispatch } } }
applyMiddleware 執(zhí)行過(guò)后返回一個(gè)閉包函數(shù),目的是將創(chuàng)建 store的步驟放在這個(gè)閉包內(nèi)執(zhí)行,這樣 middleware 就可以共享 store 對(duì)象。
middlewares 數(shù)組 map 為新的 middlewares 數(shù)組,包含了 middlewareAPI
compose 方法將新的 middlewares 和 store.dispatch 結(jié)合起來(lái),生成一個(gè)新的 dispatch 方法
返回的 store 新增了一個(gè) dispatch 方法, 這個(gè)新的 dispatch 方法是改裝過(guò)的 dispatch,也就是封裝了中間件的執(zhí)行。
所以關(guān)鍵點(diǎn)來(lái)到了 compose 方法了,下面來(lái)看一下 compose 的設(shè)計(jì):
export default function compose(...funcs) { if (funcs.length === 0) { return arg => arg } if (funcs.length === 1) { return funcs[0] } const last = funcs[funcs.length - 1] const rest = funcs.slice(0, -1) return (...args) => rest.reduceRight((composed, f) => f(composed), last(...args)) }
可以看到 compose 方法實(shí)際上就是利用了 Array.prototype.reduceRight 。如果對(duì) reduceRight 不是很熟悉,來(lái)看看下面的一個(gè)例子就清晰了:
/** * [description] * @param {[type]} previousValue [前一個(gè)項(xiàng)] * @param {[type]} currentValue [當(dāng)前項(xiàng)] */ [0, 1, 2, 3, 4].reduceRight(function(previousValue, currentValue, index, array) { return previousValue + currentValue; }, 10);
執(zhí)行結(jié)果:
# | previousValue | currentValue | return value |
---|---|---|---|
第一次 | 10 | 4 | 14 |
第二次 | 14 | 3 | 17 |
第三次 | 17 | 2 | 19 |
第四次 | 19 | 1 | 20 |
第五次 | 20 | 0 | 20 |
通過(guò)上面的 applyMiddleware 和 中間件的結(jié)構(gòu),假設(shè)應(yīng)用了如下的中間件: [A, B, C],一個(gè) action 的完整執(zhí)行流程
初始化階段一個(gè)中間件的結(jié)構(gòu)為
function ({getState}) { return function (next) { return function (action) {...} } }
初始化階段一:middlewares map 為新的 middlewares
chain = middlewares.map(middleware => middleware(middlewareAPI))
執(zhí)行過(guò)后,middleware 變?yōu)榱?/p>
function (next) { return function (action) {...} }
初始化階段二:compose 新的 dispatch
const newDispatch = compose(newMiddlewares)(store.dispatch)
dispatch 的實(shí)現(xiàn)為 reduceRight, 當(dāng)一個(gè)新的 action 來(lái)了過(guò)后
/** * 1. 初始值為: lastMiddleware(store.dispatch) * 2. previousValue: composed * 3. currentValue: currentMiddleware * 4. return value: currentMiddleware(composed) => newComposed */ rest.reduceRight((composed, f) => f(composed), last(...args))composed 流程
reduceRight 的執(zhí)行過(guò)程:
初始時(shí)候
initialValue: composedC = C(store.dispatch) = function C(action) {}
next 閉包: store.dispatch
第一次執(zhí)行:
previousValue(composed): composedC
currentValue(f): B
return value: composedBC = B(composedC) = function B(action){}
next 閉包 composedC
第二次執(zhí)行:
previousValue(composed): composedBC
currentValue(f): A
return value: composedABC = A(composedBC) = function A(action){}
next 閉包 composedBC
最后的返回結(jié)果為 composedABC
執(zhí)行階段dispatch(action) 等于 composedABC(action) 等于執(zhí)行 function A(action) {...}
在函數(shù) A 中執(zhí)行 next(action), 此時(shí) A 中 next 為 composedBC,那么等于執(zhí)行 composedBC(action) 等于執(zhí)行 function B(action){...}
在函數(shù) B 中執(zhí)行 next(action), 此時(shí) B 中 next 為 composedC,那么等于執(zhí)行 composedC(action) 等于執(zhí)行 function C(action){...}
在函數(shù) C 中執(zhí)行 next(action), 此時(shí) C 中 next 為 store.dispatch 即 store 原生的 dispatch, 等于執(zhí)行 store.dispatch(action)
store.dispatch 會(huì)執(zhí)行 reducer 生成最新的 store 數(shù)據(jù)
所有的 next 執(zhí)行完過(guò)后開(kāi)始回溯
執(zhí)行函數(shù) C 中 next 后的代碼
執(zhí)行函數(shù) B 中 next 后的代碼
執(zhí)行函數(shù) A 中 next 后的代碼
整個(gè)執(zhí)行 action 的過(guò)程為 A -> B -> C -> dispatch -> C -> B -> A
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/79743.html
摘要:舉例來(lái)說(shuō)一個(gè)異步的請(qǐng)求場(chǎng)景,可以如下實(shí)現(xiàn)任何異步的邏輯都可以,如等等也可以使用的和。實(shí)際上在中,一個(gè)就是一個(gè)函數(shù)。 書(shū)籍完整目錄 3.4 redux 異步 showImg(https://segmentfault.com/img/bVyou8); 在大多數(shù)的前端業(yè)務(wù)場(chǎng)景中,需要和后端產(chǎn)生異步交互,在本節(jié)中,將詳細(xì)講解 redux 中的異步方案以及一些異步第三方組件,內(nèi)容有: redu...
摘要:通過(guò)可以實(shí)現(xiàn)很多有趣的簡(jiǎn)潔的控制。這里默認(rèn)使用到了的一個(gè)特性,如果某一個(gè)任務(wù)成功了過(guò)后,其他任務(wù)都會(huì)被。組合是的內(nèi)關(guān)鍵字,使用的場(chǎng)景是一個(gè)。 書(shū)籍完整目錄 3.5 compose redux sages showImg(https://segmentfault.com/img/bVyoVa); 基于 redux-thunk 的實(shí)現(xiàn)特性,可以做到基于 promise 和遞歸的組合編排,而...
摘要:?jiǎn)蜗驍?shù)據(jù)流應(yīng)用的核心設(shè)計(jì)模式,數(shù)據(jù)流向自頂向下我也是性子急的人,按照技術(shù)界的慣例,在學(xué)習(xí)一個(gè)技術(shù)前,首先得說(shuō)一句。然而的單向數(shù)據(jù)流的設(shè)計(jì)讓前端定位變得簡(jiǎn)單,頁(yè)面的和數(shù)據(jù)的對(duì)應(yīng)是唯一的我們可以通過(guò)定位數(shù)據(jù)變化就可以定位頁(yè)面展現(xiàn)問(wèn)題。 書(shū)籍完整目錄 1.1 React 介紹 showImg(https://segmentfault.com/img/bVvJgS); 1.1.1 React ...
摘要:另外一點(diǎn)是組件應(yīng)該盡量保證獨(dú)立性,避免和外部的耦合,使用全局事件造成了和外部事件的耦合。明確的職責(zé)分配也增加了應(yīng)用的確定性明確只有組件能夠知道狀態(tài)數(shù)據(jù),且是對(duì)應(yīng)部分的數(shù)據(jù)。 書(shū)籍完整目錄 4.2 react patterns 修改 Props Immutable data representation 確定性 在 getInitialState 中使用 props 私有狀態(tài)和...
閱讀 2984·2021-09-10 10:50
閱讀 3188·2019-08-30 14:19
閱讀 3515·2019-08-29 17:31
閱讀 3241·2019-08-29 16:43
閱讀 2191·2019-08-29 14:05
閱讀 2088·2019-08-29 13:17
閱讀 2041·2019-08-26 13:25
閱讀 1756·2019-08-26 12:20