簡體   English   中英

使用RxJS switchMap僅取消訂閱具有相同請求URL /動作負載的流(redux-observable epics)

[英]Using RxJS switchMap to only unsubscribe from streams with the same request URL/action payload (redux-observable epics)

我有一個界面,用戶可以觸發對相同端點的調用但具有不同的參數(在本例中為UUID)。 到目前為止,每當我發送一個具有相同類型的新redux動作時,我一直很享受switchMap取消我的飛行中http請求的行為,在這種情況下我仍然想要這種行為,但只有當新動作請求UUID時(動作對象的一部分)與正在進行的動作對象相同。 我不確定正確的做法。

例如,在一次調度多個動作之后,我希望所有具有唯一ID的動作完成,但那些重復現有且尚未完成的id的動作將取消之前的請求並取代它。

例如:

store.dispatch({ type: "GET_SOME_DATA", uuid: "1" })
store.dispatch({ type: "GET_SOME_DATA", uuid: "2" })
store.dispatch({ type: "GET_SOME_DATA", uuid: "2" })
store.dispatch({ type: "GET_SOME_DATA", uuid: "3" })
store.dispatch({ type: "GET_SOME_DATA", uuid: "2" })
// Get results back for '1', then '3', then '2' assuming equal response times.
// Only the duplicate uuid calls were cancelled, even though all have the same 'type'

我嘗試過使用.distinctUntilChanged((a, b) => a.uuid === b.uuid)將流的輸入過濾到.switchMap只是為了看看會發生什么,但這只是限制了哪些動作到達了switchMap ,並且仍然會發生取消除最近的GET_SOME_DATA操作相關的API調用GET_SOME_DATA所有行為。

const getDataEpic = (action$) =>
  action$.ofType(GET_SOME_DATA)
    .switchMap(({ uuid }) => // would be great if the switchMap would only cancel existing streams with same uuid
      ajax.getJSON(`/api/datastuff/${uuid}`)
        .map((data) => successAction(uuid, data.values))
        .catch((err) => Observable.of(
          errorAction(uuid),
          setNotificationAction((err.xhr.response && err.xhr.response.message) || 'That went wrong'),
        ))

現在,我正在使用mergeMap ,但我擔心這可能會導致我遇到的問題,例如我遇到了較舊的請求可能會在最近的請求之后解決,導致我的redux存儲更新舊數據因為mergeMap沒有像switchMap那樣取消Observable流......有沒有辦法讓我查看當前的RxJS Ajax請求並取消那些使用新動作的url,或者是一個我明顯遺漏的更好的解決方案?

干杯!

編輯:我想知道是否將switchMap更改為mergeMap ,然后鏈接takeUntil並取消其他GET_SOME_DATA操作將是一種正確的方法,或者如果這只會立即取消所有請求? 例如

const getDataEpic = (action$) =>
  action$.ofType(GET_SOME_DATA)
    .mergeMap(({ uuid }) =>
      ajax.getJSON(`/api/datastuff/${uuid}`)
        .takeUntil(
          action$.ofType(GET_SOME_DATA).filter(laterAction => laterAction.uuid === uuid)
        )
        .map((data) => successAction(uuid, data.values))
        .catch((err) => Observable.of(
          errorAction(uuid),
          setNotificationAction((err.xhr.response && err.xhr.response.message) || 'That went wrong'),
    ))

Edit2:顯然, takeUntil添加似乎正在工作! 我不確定它是否100%在適當的方面上升,但我喜歡一些反饋。 我也想支持手動取消選項, 這里討論的方法是否正確實施?

編輯3:我認為這是我最后的工作版本。 刪除了mergeMap中Redux動作的解構,以防有人看到redux-observables更新:

const getDataEpic = (action$) =>
  action$.ofType(GET_SOME_DATA)
    .mergeMap((action) =>
      ajax.getJSON(`/api/datastuff/${action.uuid}`)
        .takeUntil(Observable.merge(
          action$.ofType(MANUALLY_CANCEL_GETTING_DATA)
            .filter((cancelAction) => cancelAction.uuid === action.uuid),
          action$.ofType(GET_SOME_DATA)
            .filter((laterAction) => laterAction.uuid === action.uuid),
        ))
        .map((data) => successAction(action.uuid, data.values))
        .catch((err) => Observable.of(
          errorAction(action.uuid),
          setNotificationAction((err.xhr.response && err.xhr.response.message) || 'That went wrong'),
    ))

並且通過快速點擊所看到的一切來觀察網絡行為。 只有非重復的ID請求通過!

在此輸入圖像描述

您還可以使用groupBy運算符來處理具有相同uuid的流,並在每個uuid操作流上應用有用的switchMap行為:

action$.ofType(GET_SOME_DATA)
.groupBy(
    ({ uuid }) => uuid, // group all the actions by uuid
    x => x,
    group$ => group$.switchMap(_ => Observable.timer(5000)) // close existing streams if no event of a grouped action is emitted 5 seconds in a row (prevents memory leaks)
)
.mergeMap(actionsGroupedByUuid$ => 
    actionsGroupedByUuid$.switchMap(({ uuid }) => 
        ajax.getJSON(`/api/datastuff/${uuid}`)
            .map((data) => successAction(uuid, data.values))
            .catch((err) => Observable.of(
                errorAction(uuid),
                setNotificationAction((err.xhr.response && err.xhr.response.message) || 'That went wrong'),
            )) 
    )
);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM