最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

redux功能強(qiáng)大的Middleware中間件使用學(xué)習(xí)

 更新時(shí)間:2022年09月07日 08:42:57   作者:文奇  
這篇文章主要為大家介紹了redux功能強(qiáng)大的Middleware中間件使用學(xué)習(xí),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

引言

上一節(jié)我們學(xué)習(xí)了redux在實(shí)際項(xiàng)目的應(yīng)用細(xì)節(jié),這一節(jié)我們來(lái)學(xué)習(xí)redux中一個(gè)很重要的概念:中間件。我們會(huì)簡(jiǎn)單實(shí)現(xiàn)一個(gè)記錄的中間件, 然后學(xué)習(xí)redux-saga這個(gè)異步請(qǐng)求中間件。

redux中的Middleware

redux中的中間件提供的是位于 action 被發(fā)起之后,到達(dá) reducer 之前的擴(kuò)展點(diǎn)。 你可以利用 Redux middleware 來(lái)進(jìn)行日志記錄、創(chuàng)建崩潰報(bào)告、調(diào)用異步接口或者路由等等。

記錄日志

試想一下,如果我們的redux在每一次dispatch的時(shí)候都可以記錄下此次發(fā)生的action以及dispatch結(jié)束后的store。那么在我們的應(yīng)用 出現(xiàn)問(wèn)題的時(shí)候,我們就可以輕松的查閱日志找出是哪個(gè)action導(dǎo)致了state不正確。那么我們?cè)鯓油ㄟ^(guò)redux實(shí)現(xiàn)它呢?

手動(dòng)記錄

最直接的解決方案就是在每次調(diào)用 store.dispatch(action) 前后手動(dòng)記錄被發(fā)起的 action 和新的 state。假如你在創(chuàng)建一個(gè)action時(shí)這樣調(diào)用:

store.dispatch(addTodo('use Redux'))

為了記錄這個(gè) action 以及產(chǎn)生的新的 state,你可以通過(guò)這種方式記錄日志:

let action = addTodo('Use Redux')
console.log('dispatching', action)
store.dispatch(action)
console.log('next state', store.getState())

那么很自然的就能想到可以封裝為一個(gè)函數(shù)在各處調(diào)用:

function dispatchAndLog(store, action) {
  console.log('dispatching', action)
  store.dispatch(action)
  console.log('next state', store.getState())
} 
dispatchAndLog(store, addTodo('Use Redux'))

但是這樣我們還是需要每次導(dǎo)入一個(gè)外部方法,那么如果我們直接去替換store實(shí)例中的dispatch函數(shù)呢?

let next = store.dispatch
store.dispatch = function dispatchAndLog(action) {
  console.log('dispatching', action)
  let result = next(action)
  console.log('next state', store.getState())
  return result
}

其實(shí)到這里我們想要實(shí)現(xiàn)的功能已經(jīng)完成了,但是距離Middleware實(shí)際使用的方法還是有不小的差距, 同時(shí)我們這里只能對(duì)dispatch的擴(kuò)展時(shí)十分有限的,如果我想對(duì)其添加其他的功能,又該怎么實(shí)現(xiàn)呢? 首先可以確定的是我們需要將每一個(gè)功能分離開(kāi)來(lái),我們希望的時(shí)一個(gè)功能對(duì)應(yīng)一個(gè)模塊,那么當(dāng)我們想添加其他的模塊時(shí),應(yīng)該是這樣的:

function patchStoreToAddLogging(store) {
  let next = store.dispatch
  store.dispatch = function dispatchAndLog(action) {
    console.log('dispatching', action)
    let result = next(action)
    console.log('next state', store.getState())
    return result
  }
}
// 崩潰報(bào)告模塊
function patchStoreToAddCrashReporting(store) {
  let next = store.dispatch
  store.dispatch = function dispatchAndReportErrors(action) {
    try {
      return next(action)
    } catch (err) {
      console.error('捕獲一個(gè)異常!', err)
      Raven.captureException(err, {
        extra: {
          action,
          state: store.getState()
        }
      })
      throw err
    }
  }
}

然后我們可以在store中使用它們:

patchStoreToAddLogging(store)
patchStoreToAddCrashReporting(store)

那么有沒(méi)有一種更好的代碼組織方式呢?此前,我們使用dispatchAndLog替換了dispatch, 如果我們不這樣做,而是在函數(shù)中返回新的dispatch呢?

function logger(store) {
  let next = store.dispatch
  // 我們之前的做法:
  // store.dispatch = function dispatchAndLog(action) {
  return function dispatchAndLog(action) {
    console.log('dispatching', action)
    let result = next(action)
    console.log('next state', store.getState())
    return result
  }
}

然后我們?cè)谕獠刻峁┓椒▽⑺鎿Q到store.dispatch中。

function applyMiddlewareByMonkeypatching(store, middlewares) {
  middlewares = middlewares.slice()
  middlewares.reverse()
  // 在每一個(gè) middleware 中變換 dispatch 方法。
  middlewares.forEach(middleware =>
    store.dispatch = middleware(store)
  )
}

其實(shí)到了這里我們的中間件功能已經(jīng)大體實(shí)現(xiàn),如果想后續(xù)繼續(xù)深入請(qǐng)參考redux官方文檔

redux-saga

接下來(lái)我們來(lái)看管理應(yīng)用程序副作用的中間件reudx-saga。他在redux中有很多使用場(chǎng)景,但是我們使用最多的還是用它來(lái)進(jìn)行網(wǎng)絡(luò)請(qǐng)求。

redux-saga使用了ES6的Generator功能,讓異步的流程更易于讀取,寫(xiě)入和測(cè)試。因此我們首先了解一下generator函數(shù)是什么?

Generator函數(shù)

形式上,Generator函數(shù)是一個(gè)普通函數(shù),但是有兩個(gè)特征。

一是,function關(guān)鍵字與函數(shù)名之間有一個(gè)星號(hào);

二是,函數(shù)體內(nèi)部使用yield表達(dá)式,定義不同的內(nèi)部狀態(tài).

function* helloWorldGenerator() {
  yield 'hello';
  yield 'world';
  return 'ending';
}
const hw = helloWorldGenerator();

Generator 函數(shù)的調(diào)用方法與普通函數(shù)一樣,也是在函數(shù)名后面加上一對(duì)圓括號(hào)。不同的是,調(diào)用 Generator 函數(shù)后,該函數(shù)并不執(zhí)行,返回的也不是函數(shù)運(yùn)行結(jié)果,而是一個(gè)指向內(nèi)部狀態(tài)的指針對(duì)象。

下一步,必須調(diào)用遍歷器對(duì)象的next方法,使得指針移向下一個(gè)狀態(tài)。也就是說(shuō),每次調(diào)用next方法,內(nèi)部指針就從函數(shù)頭部或上一次停下來(lái)的地方開(kāi)始執(zhí)行,直到遇到下一個(gè)yield表達(dá)式(或return語(yǔ)句)為止。

換言之,Generator 函數(shù)是分段執(zhí)行的,yield表達(dá)式是暫停執(zhí)行的標(biāo)記,而next方法可以恢復(fù)執(zhí)行

hw.next()
// { value: 'hello', done: false }
hw.next()
// { value: 'world', done: false }
hw.next()
// { value: 'ending', done: true }
hw.next()
// { value: undefined, done: true }

實(shí)際使用場(chǎng)景

現(xiàn)在來(lái)看一個(gè)項(xiàng)目中的實(shí)際使用

//查詢搜索列表
const requestLists = function*({ page, keyword, callback }) {
  try {
    appLoading(); // 展現(xiàn)加載框
    const body = {
      keyword: keyword,
      page: page,
      size: size,
    };
    const result = yield handleData.get(DataUrls.searchLists, body) // 發(fā)送網(wǎng)絡(luò)請(qǐng)求
    if (result && result.success) {
      yield put(Action.fetchSearchListDone(lists)); // 請(qǐng)求成功保存數(shù)據(jù)
      callback && callback();
    } else {
      showModal((result && result.message) || '系統(tǒng)繁忙,請(qǐng)稍后'); 
      yield put(Action.fetchSearchListFailure(result)); //請(qǐng)求失敗錯(cuò)誤處理
    }
  } catch (err) {
    yield put(Action.fetchSearchListFailure(err)); //錯(cuò)誤處理
    showModal('系統(tǒng)繁忙,請(qǐng)稍后');
  } finally {
    appFinish(); //關(guān)閉加載框
  }
};

上面是一個(gè)比較完整的請(qǐng)求處理過(guò)程,從發(fā)送請(qǐng)求到成功或失敗處理都有包含到。

對(duì)上面的代碼做一個(gè)解釋,在這個(gè)函數(shù)中我們首先使用yield發(fā)起一個(gè)異步請(qǐng)求,這時(shí)middleware 會(huì)暫停 Saga,直到請(qǐng)求完成。 一旦完成后,不管是成功或者失敗,middleware 會(huì)恢復(fù) Saga 接著執(zhí)行,直到遇到下一個(gè) yield。當(dāng) try 報(bào)錯(cuò)時(shí), 會(huì)執(zhí)行到catch去捕獲異常, 在這里遇到下一個(gè)yield,調(diào)用請(qǐng)求失敗的Action,傳入失敗原因。請(qǐng)求成功時(shí)遇到下一個(gè) yield 對(duì)象,調(diào)用請(qǐng)求成功的Action,傳入結(jié)果。

put 就是我們稱作副作用的一個(gè)例子。副作用是一些簡(jiǎn)單 Javascript 對(duì)象,包含了要被 middleware 執(zhí)行的指令。 當(dāng) middleware 拿到一個(gè)被 Saga yield 的副作用,它會(huì)暫停 Saga,直到副作用執(zhí)行完成,然后 Saga 會(huì)再次被恢復(fù)。

接下來(lái)我們需要去啟動(dòng)這個(gè)saga,為了做到這一點(diǎn),我們將添加一個(gè) listSaga,負(fù)責(zé)啟動(dòng)其他的 Sagas。在同一個(gè)文件中:

const listSagas = function* listSagas() {
  yield all([
    takeEvery('LIST_REQUESTLIST', requestLists),
  ]);
};
export default listSagas;

其中的輔助函數(shù)takeEvery用于監(jiān)聽(tīng)所有的LIST_REQUESTLISTaction,在action執(zhí)行的時(shí)候去啟動(dòng)相應(yīng)的requestLists任務(wù)。 定義一個(gè)listSagas的原因就是我們這個(gè)文件中可能遠(yuǎn)不至這一個(gè)副作用函數(shù),當(dāng)定義了多個(gè)的時(shí)候,我們可以在all中添加一個(gè)takeEvery, 這樣就會(huì)有兩個(gè)Generators同時(shí)啟動(dòng)。在實(shí)際項(xiàng)目中因?yàn)轫?xiàng)目所分的模塊可能會(huì)有很多,因此對(duì)每個(gè)模塊都定義一個(gè)sagas是很有必要的, 最終在sagas的最外層定義一個(gè)index.js文件用來(lái)將我們的所有模塊整合在一起定義一個(gè)root,然后我們只有在 main.js 的 root Saga 中調(diào)用sagaMiddleware.run。就可以啟動(dòng)所有的sagas。

對(duì)于其他更加詳細(xì)的redux-saga學(xué)習(xí)可以參考文檔

以上就是redux功能強(qiáng)大的Middleware中間件使用學(xué)習(xí)的詳細(xì)內(nèi)容,更多關(guān)于redux中間件Middleware的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 簡(jiǎn)單的React SSR服務(wù)器渲染實(shí)現(xiàn)

    簡(jiǎn)單的React SSR服務(wù)器渲染實(shí)現(xiàn)

    這篇文章主要介紹了簡(jiǎn)單的React SSR服務(wù)器渲染實(shí)現(xiàn),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-12-12
  • 深入了解響應(yīng)式React Native Echarts組件

    深入了解響應(yīng)式React Native Echarts組件

    近年來(lái),隨著移動(dòng)端對(duì)數(shù)據(jù)可視化的要求越來(lái)越高,通過(guò) WebView 在移動(dòng)端使用 Echarts 這樣功能強(qiáng)大的前端數(shù)據(jù)可視化庫(kù),是解決問(wèn)題的好辦法。下面就和小編來(lái)一起學(xué)習(xí)一下吧
    2019-05-05
  • 詳解React-Native解決鍵盤(pán)遮擋問(wèn)題(Keyboard遮擋問(wèn)題)

    詳解React-Native解決鍵盤(pán)遮擋問(wèn)題(Keyboard遮擋問(wèn)題)

    本篇文章主要介紹了React-Native解決鍵盤(pán)遮擋問(wèn)題(Keyboard遮擋問(wèn)題),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-07-07
  • 路由react-router-dom的基本使用教程

    路由react-router-dom的基本使用教程

    在React中,路由是一套映射規(guī)則,是URL路徑與組件的對(duì)應(yīng)關(guān)系。使用React路由,就是配置路徑和組件的對(duì)應(yīng)關(guān)系,這篇文章主要介紹了路由react-router-dom的使用,需要的朋友可以參考下
    2023-02-02
  • React組件重構(gòu)之嵌套+繼承及高階組件詳解

    React組件重構(gòu)之嵌套+繼承及高階組件詳解

    這篇文章主要給大家介紹了關(guān)于React組件重構(gòu)之嵌套+繼承及高階組件的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2018-07-07
  • React服務(wù)端渲染和同構(gòu)的實(shí)現(xiàn)

    React服務(wù)端渲染和同構(gòu)的實(shí)現(xiàn)

    本文主要介紹了React服務(wù)端渲染和同構(gòu)的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-04-04
  • React 實(shí)現(xiàn)拖拽功能的示例代碼

    React 實(shí)現(xiàn)拖拽功能的示例代碼

    這篇文章主要介紹了React 實(shí)現(xiàn)拖拽功能的示例代碼,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2019-01-01
  • 從零開(kāi)始搭建webpack+react開(kāi)發(fā)環(huán)境的詳細(xì)步驟

    從零開(kāi)始搭建webpack+react開(kāi)發(fā)環(huán)境的詳細(xì)步驟

    這篇文章主要介紹了從零開(kāi)始搭建webpack+react開(kāi)發(fā)環(huán)境的詳細(xì)步驟,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-05-05
  • 前端框架react-spring基礎(chǔ)用法

    前端框架react-spring基礎(chǔ)用法

    這篇文章主要為大家介紹了前端框架react-spring基礎(chǔ)用法示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-04-04
  • React useState的錯(cuò)誤用法避坑詳解

    React useState的錯(cuò)誤用法避坑詳解

    這篇文章主要為大家介紹了React useState的錯(cuò)誤用法避坑詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-01-01

最新評(píng)論

河西区| 建湖县| 合川市| 石家庄市| 山阴县| 临猗县| 黔江区| 三河市| 渭南市| 东丽区| 寿阳县| 拉萨市| 界首市| 保靖县| 江北区| 嘉义市| 新干县| 南昌市| 万年县| 秭归县| 青海省| 绥江县| 冕宁县| 安顺市| 金川县| 东乡| 玉屏| 平谷区| 江西省| 玉山县| 石景山区| 崇明县| 句容市| 台南市| 固原市| 天气| 余姚市| 邵阳市| 池州市| 岗巴县| 甘泉县|