摘要:當(dāng)你應(yīng)用了中間件,在觸發(fā)一個(gè)操作的時(shí)候,操作就會(huì)經(jīng)過先經(jīng)過中間件,最終再形成。以其中兩個(gè)中間件為例,說明下,一個(gè)觸發(fā)一個(gè)動(dòng)作的時(shí)候,代碼的執(zhí)行邏輯。
為了解析中間件,先看一下幾個(gè)中間件是什么樣子,怎么用,運(yùn)行起來的原理是什么?
1、中間件是什么樣子的 1.2 thunk中間件function createThunkMiddleware(extraArgument) { return ({ dispatch, getState }) => next => action => { // 如果是函數(shù),就執(zhí)行函數(shù) if (typeof action === "function") { return action(dispatch, getState, extraArgument); } // 如果不是,執(zhí)行下一個(gè)中間件 return next(action); }; } const thunk = createThunkMiddleware(); thunk.withExtraArgument = createThunkMiddleware; export default thunk;1.2promise中間件
import isPromise from "is-promise"; import { isFSA } from "flux-standard-action"; export default function promiseMiddleware({ dispatch }) { return next => action => { if (!isFSA(action)) { return isPromise(action) ? action.then(dispatch) : next(action); } return isPromise(action.payload) ? action.payload .then(result => dispatch({ ...action, payload: result })) .catch(error => { dispatch({ ...action, payload: error, error: true }); return Promise.reject(error); }) : next(action); }; }1.3logger中間件
const defaultLogger = ({ dispatch, getState } = {}) => { if (typeof dispatch === "function" || typeof getState === "function") { return createLogger()({ dispatch, getState }); } }; function createLogger(options = {}) { const loggerOptions = Object.assign({}, defaults, options); const { logger, stateTransformer, errorTransformer, predicate, logErrors, diffPredicate, } = loggerOptions; if (typeof logger === "undefined") { return () => next => action => next(action); } import { logger } from "redux-logger" const store = createStore( reducer, applyMiddleware(logger)) import { createLogger } from "redux-logger" const logger = createLogger({ // ...options }); const store = createStore( reducer, applyMiddleware(logger)); return () => next => action => next(action); } const logBuffer = []; return ({ getState }) => next => (action) => { if (typeof predicate === "function" && !predicate(getState, action)) { return next(action); } const logEntry = {}; logBuffer.push(logEntry); logEntry.started = timer.now(); logEntry.startedTime = new Date(); logEntry.prevState = stateTransformer(getState()); logEntry.action = action; let returnedValue; if (logErrors) { try { returnedValue = next(action); } catch (e) { logEntry.error = errorTransformer(e); } } else { returnedValue = next(action); } logEntry.took = timer.now() - logEntry.started; logEntry.nextState = stateTransformer(getState()); const diff = loggerOptions.diff && typeof diffPredicate === "function" ? diffPredicate(getState, action) : loggerOptions.diff; printBuffer(logBuffer, Object.assign({}, loggerOptions, { diff })); logBuffer.length = 0; if (logEntry.error) throw logEntry.error; return returnedValue; }; } export { defaults, createLogger, defaultLogger as logger }; export default defaultLogger;2、怎么使用中間件
const store = createStore(rootReducer, initialState, applyMiddleware(thunk), ... ... );
簡(jiǎn)單來說,createStore做了這么件事:
目的:根據(jù)你傳入的reducer和初始狀態(tài)initialState生成初始化store,并提供了一些列操作的接口,像dispatch等
怎么做的呢?參考Redux-creatStore/compose
本文重點(diǎn)講解中間件的執(zhí)行過程和原理
中間件的執(zhí)行原理和koa中間件的執(zhí)行原理類似,但是不是洋蔥型的,而是半個(gè)洋蔥,因?yàn)閞edux是單向執(zhí)行的,走過去就完事了。
當(dāng)你應(yīng)用了中間件,在觸發(fā)一個(gè)action操作的時(shí)候,action操作就會(huì)經(jīng)過先經(jīng)過中間件,最終再形成dispatch(action)。
以其中兩個(gè)中間件為例,說明下,一個(gè)觸發(fā)一個(gè)action動(dòng)作的時(shí)候,代碼的執(zhí)行邏輯。
thunk:是允許dispatch一個(gè)函數(shù),而不是一個(gè)對(duì)象
假如說異步打印一個(gè)日志。
const store = createStore(reducer, preloadedState, enchancer); // 如果沒有中間件,正常觸發(fā)一個(gè)action; // 如果有中間件的時(shí)候 creatStore內(nèi)部的執(zhí)行邏輯是這樣的 // enchancer 就是你應(yīng)用的中間件,調(diào)用applyMiddleware得到的組合中間件 function applyMiddleware(...middlewares) { return createStore => (...args) => { // 該創(chuàng)建的store還是要?jiǎng)?chuàng)建的,只傳入了兩個(gè)參數(shù),沒有中間件,得到的是正常的store const store = createStore(...args) let dispatch = () => { throw new Error( `Dispatching while constructing your middleware is not allowed. ` + `Other middleware would not be applied to this dispatch.` ) } // 把getState、dispatch傳給中間件 const middlewareAPI = { getState: store.getState, dispatch: (...args) => dispatch(...args) } // 下面方法返回來了一個(gè)函數(shù)數(shù)組,中間件被剝離到 // next => {} const chain = middlewares.map(middleware => middleware(middlewareAPI)) // 再執(zhí)行下面的,中間件就被剝離到 // action => {} dispatch = compose(...chain)(store.dispatch) return { ...store, dispatch } } } // 下面得到的結(jié)果是 // 假設(shè)中間件為 a b // a(b(store.dispatch)) return enchancer(createStore)(reducer, preloadedState); // 結(jié)合上面thunk的源碼 ({ dispatch, getState }) => next => action => { if (typeof action === "function") { return action(dispatch, getState); } return next(action); };
經(jīng)過上面的操作后,經(jīng)過中間件包裝后的store是什么樣子
假設(shè)中間件為 a b c
沒有中間件的時(shí)候是這樣的
store = { dispatch, ... ..., subscribe, getState }
經(jīng)過中間包裝后,store變成了
store = { dispatch: a(b((store.dispatch))), ... ..., subscribe, getState }
總結(jié)起來就是給每一個(gè)中間件配發(fā)了一個(gè)原始store的dispatch,中間件函數(shù)嵌套執(zhí)行
3.2 觸發(fā)一個(gè)action時(shí),執(zhí)行邏輯假設(shè)觸發(fā)一個(gè)異步打印日志的功能
應(yīng)用中間件
const store = createStore(rootReducer, initialState, applyMiddleware(thunk) );
經(jīng)過上面的操作,現(xiàn)在的store應(yīng)該是
{ dispatch: action => { if (typeof action === "function") { return action(dispatch, getState, extraArgument); } return next(action); }, ... ..., subscribe, getState }
action函數(shù)
當(dāng)執(zhí)行這個(gè)logNext的時(shí)候,返回一個(gè)函數(shù),函數(shù)的參數(shù)是dispatch和getState兩個(gè)。
const logNext = () => (dispatch, getState) => { setTimeout( dispatch({ type: "LOG", payload: { content: "這是一條異步日志" }}) ,5000); }
執(zhí)行過程
----> store.dispatch(logNext()) // 傳了一個(gè)函數(shù),然后執(zhí)行一個(gè)函數(shù) ----> (dispatch, getState) => { setTimeout( dispatch({ type: "LOG", payload: { content: "這是一條異步日志" }}) ,5000); } ---->
可以看出來,redux-thunk就是一個(gè)封裝函數(shù),允許store.dispatch一個(gè)函數(shù)
如果有多個(gè)中間件,執(zhí)行過程是什么樣子的?重點(diǎn)在next(action),next是什么呢?
next就是每一個(gè)中間件要做的事情
next => action => {}
明白了么?
附錄 compsoe// compose本身并不改變函數(shù)的執(zhí)行,將函數(shù)組合后又返回了一個(gè)函數(shù) function compose(...funcs) { if (funcs.length === 0) { return arg => arg } if (funcs.length === 1) { return funcs[0] } return funcs.reduce((a, b) => (...args) => a(b(...args))) }
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/98334.html
摘要:通過創(chuàng)建將所有的異步操作邏輯收集在一個(gè)地方集中處理,可以用來代替中間件。 redux-saga框架使用詳解及Demo教程 前面我們講解過redux框架和dva框架的基本使用,因?yàn)閐va框架中effects模塊設(shè)計(jì)到了redux-saga中的知識(shí)點(diǎn),可能有的同學(xué)們會(huì)用dva框架,但是對(duì)redux-saga又不是很熟悉,今天我們就來簡(jiǎn)單的講解下saga框架的主要API和如何配合redux框...
摘要:或者兄弟組件之間想要共享某些數(shù)據(jù),也不是很方便傳遞獲取等。后面要講到的就是通過讓各個(gè)子組件拿到中的數(shù)據(jù)的。所以,確實(shí)和沒有什么本質(zhì)關(guān)系,可以結(jié)合其他庫正常使用。 本文介紹了react、redux、react-redux之間的關(guān)系,分享給大家,也給自己留個(gè)筆記,具體如下: React 一些小型項(xiàng)目,只使用 React 完全夠用了,數(shù)據(jù)管理使用props、state即可,那什么時(shí)候需要引入...
摘要:執(zhí)行完后,獲得數(shù)組,,它保存的對(duì)象是圖中綠色箭頭指向的匿名函數(shù),因?yàn)殚]包,每個(gè)匿名函數(shù)都可以訪問相同的,即。是函數(shù)式編程中的組合,將中的所有匿名函數(shù),,組裝成一個(gè)新的函數(shù),即新的,當(dāng)新執(zhí)行時(shí),,從左到右依次執(zhí)行所以順序很重要。 前言 It provides a third-party extension point between dispatching anaction, and t...
閱讀 923·2023-04-26 01:34
閱讀 3356·2023-04-25 20:58
閱讀 3262·2021-11-08 13:22
閱讀 2108·2019-08-30 14:17
閱讀 2522·2019-08-29 15:27
閱讀 2673·2019-08-29 12:45
閱讀 2996·2019-08-29 12:26
閱讀 2811·2019-08-28 17:51