[英]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.