日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

redux异步action_React躬行记(12)——Redux中间件

發(fā)布時(shí)間:2023/12/2 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 redux异步action_React躬行记(12)——Redux中间件 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

  Redux的中間件(Middleware)遵循了即插即用的設(shè)計(jì)思想,出現(xiàn)在Action到達(dá)Reducer之前(如圖10所示)的位置。中間件是一個(gè)固定模式的獨(dú)立函數(shù),當(dāng)把多個(gè)中間件像管道那樣串聯(lián)在一起時(shí),前一個(gè)中間件不但能將其輸出傳給下一個(gè)中間件作為輸入,還能中斷整條管道。在引入中間件后,既能擴(kuò)展Redux的功能,也能增強(qiáng)dispatch()函數(shù),適應(yīng)不同的業(yè)務(wù)需求,例如通過中間件記錄日志、報(bào)告奔潰或處理異步請(qǐng)求等。

圖10 中間件管道

一、開發(fā)模式

  在設(shè)計(jì)中間件函數(shù)時(shí),會(huì)遵循一個(gè)固定的模式,如下代碼所示,使用了柯里化、高階函數(shù)等函數(shù)式編程中的概念。

function middleware(store) {return function(next) {return function(action) {return next(action);};}; }

  middleware()函數(shù)接收一個(gè)Store實(shí)例,返回值是一個(gè)接收next參數(shù)的函數(shù)。其中next也是一個(gè)函數(shù),用來將控制權(quán)轉(zhuǎn)移給下一個(gè)中間件,從而實(shí)現(xiàn)了中間件之間的串聯(lián),它會(huì)返回一個(gè)處理Action對(duì)象的函數(shù)。由于閉包的作用,在這最內(nèi)層的函數(shù)中,依然能調(diào)用外層的對(duì)象和函數(shù),例如訪問action所攜帶的數(shù)據(jù)、執(zhí)行store中的dispatch()或getState()方法等。示例中的middleware()函數(shù)只是單純的將接收到的action對(duì)象轉(zhuǎn)交給后面的中間件,沒有對(duì)其做額外的處理。

  之所以將中間件函數(shù)寫成層層嵌套的模式,有以下幾個(gè)原因。

(1)擴(kuò)展Redux需要遵循函數(shù)式編程的設(shè)計(jì)思想。

(2)柯里化讓中間件更容易處理數(shù)據(jù)流,即便于形成數(shù)據(jù)處理管道。

(3)每個(gè)中間件的職責(zé)單一(即函數(shù)代碼盡量少),通過嵌套組合完成復(fù)雜功能。

  利用ES6中的箭頭函數(shù)能將middleware()函數(shù)改寫得更加簡(jiǎn)潔,如下所示。

const middleware = store => next => action => {return next(action); };

二、applyMiddleware()

  Redux提供了組織中間件的applyMiddleware()函數(shù),在閱讀過此函數(shù)的源碼(如下所示)之后,才能更好的理解中間件的開發(fā)模式。

function applyMiddleware(...middlewares) {return createStore => (...args) => {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.");};const middlewareAPI = {getState: store.getState,dispatch: (...args) => dispatch(...args)};const chain = middlewares.map(middleware => middleware(middlewareAPI));dispatch = compose(...chain)(store.dispatch);return { ...store, dispatch };}; }

1)源碼分析

  接下來會(huì)分析函數(shù)中的代碼,為了便于理解,在說明中還會(huì)給出相應(yīng)的語(yǔ)句。

  (1)利用剩余參數(shù)(...middlewares)的方式,applyMiddleware()函數(shù)可以接收任意多個(gè)中間件。

  (2)返回一個(gè)接收createStore參數(shù)的函數(shù),在函數(shù)體中調(diào)用Redux的createStore()函數(shù),得到一個(gè)store實(shí)例。

const store = createStore(...args);

  (3)middlewareAPI變量包含了中間件需要的參數(shù),即store.getState()和dispatch()方法。

const middlewareAPI = {getState: store.getState,dispatch: (...args) => dispatch(...args) };

  (4)將middlewareAPI變量傳遞給每個(gè)中間件并調(diào)用一次,再將返回的函數(shù)組成一個(gè)新數(shù)組。

const chain = middlewares.map(middleware => middleware(middlewareAPI));

  (5)通過compose()增強(qiáng)dispatch()方法,compose()是Redux內(nèi)置的函數(shù),可從右向左合成多個(gè)函數(shù),例如compose(f1, f2, f3)(arg)相當(dāng)于f1(f2(f3(arg)))。

dispatch = compose(...chain)(store.dispatch);

  (6)最終得到一個(gè)對(duì)象,包含store實(shí)例的方法和增強(qiáng)后的dispatch()方法。

return { ...store, dispatch };

2)使用方式

  applyMiddleware()函數(shù)有兩種使用方式,下面用一個(gè)例子來演示,先定義兩個(gè)中間件:m1和m2,以及一個(gè)Reducer函數(shù):caculate()。

const m1 = store => next => action => {console.log("m1");return next(action); }; const m2 = store => next => action => {console.log("m2");return next(action); }; function caculate(previousState = {digit:0}, action) {let state = Object.assign({}, previousState);switch (action.type) {case "ADD":state.digit += 1;break;case "MINUS":state.digit -= 1;}return state; }

  (1)applyMiddleware()是一個(gè)三級(jí)柯里化的函數(shù),如果要使用,那么可以像下面這樣調(diào)用,先傳兩個(gè)中間件,再傳createStore()函數(shù),最后傳caculate()函數(shù)。

let store = applyMiddleware(m1, m2)(createStore)(caculate);

  (2)applyMiddleware()函數(shù)還可以作為createStore()的最后一個(gè)參數(shù),如下代碼所示,第一個(gè)參數(shù)是caculate()函數(shù),第二個(gè)參數(shù)是applyMiddleware()函數(shù)的結(jié)果。

let store = createStore(caculate, applyMiddleware(m1, m2));

  在applyMiddleware()函數(shù)的內(nèi)部,chain數(shù)組的值是[m1(next), m2(next)],由m1和m2返回的包含next參數(shù)的函數(shù)組成。增強(qiáng)后的dispatch()方法通過m1(m2(store.dispatch))得到,具體如下所示。

dispatch = action => {console.log("m1");return next(action); };

  當(dāng)調(diào)用store實(shí)例的dispatch()方法(如下代碼所示)時(shí),會(huì)先輸出“m1”;然后調(diào)用next()函數(shù),也就是m2(next),輸出“m2”;最后調(diào)用m2中的next()函數(shù),也就是dispatch()方法。注意,不能在中間件中直接調(diào)用dispatch()方法,以免造成死循環(huán)。

store.dispatch({ type: "ADD" });

三、redux-thunk

  如果要在Redux中處理異步請(qǐng)求,那么可以借助中間件實(shí)現(xiàn),目前市面上已有很多封裝好的中間件可供使用,例如redux-thunk、redux-promise或redux-saga等。本節(jié)將著重講解redux-thunk中間件,其核心代碼如下所示。

function createThunkMiddleware(extraArgument) {return ({ dispatch, getState }) => next => action => {if (typeof action === "function") {return action(dispatch, getState, extraArgument);}return next(action);}; }

  首先檢測(cè)action的類型,如果是函數(shù),那么就直接調(diào)用并將dispatch、getState和extraArgument作為參數(shù)傳入;否則就調(diào)用next參數(shù),轉(zhuǎn)移控制權(quán)。redux-thunk其實(shí)擴(kuò)展了dispatch()方法,使其參數(shù)既可以是JavaScript對(duì)象,也可以是函數(shù)。

  接下來用一個(gè)簡(jiǎn)單的例子演示redux-thunk的用法,如下代碼所示,首先通過import引入redux-thunk,并定義一個(gè)異步Action。

import thunk from "redux-thunk"; function asynAction() {return dispatch => {fetch("server.php").then(response => response.json(),error => console.log(error)).then(data => {dispatch(data); //{type: "ADD"}});}; }

  然后讓asynAction()函數(shù)返回一個(gè)接收dispatch參數(shù)的函數(shù),在函數(shù)體內(nèi)通過fetch()函數(shù)請(qǐng)求服務(wù)端的資源,再利用得到的Promise處理獲取到的數(shù)據(jù)。在第二個(gè)then()方法中,data參數(shù)被賦為{type: "ADD"},也就是server.php響應(yīng)的數(shù)據(jù),其代碼如下所示。

<?php $json = ['type' => 'ADD' ]; echo json_encode($json);

  再接入redux-thunk中間件,即將thunk傳給applyMiddleware()函數(shù),最后發(fā)送一個(gè)異步Action,如下所示。

let store = createStore(caculate, applyMiddleware(thunk)); store.dispatch(asynAction());

總結(jié)

以上是生活随笔為你收集整理的redux异步action_React躬行记(12)——Redux中间件的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。