Using RxJS switchMap to only unsubscribe from streams with the same request URL/action payload (redux-observable epics)
我有一个界面,用户可以在该界面中触发对同一终结点但具有不同参数(在本例中为UUID)的调用。到目前为止,每当我分派具有相同类型的新redux操作时,我就一直享受
例如,在一次调度多个动作之后,我希望所有具有唯一ID的动作都已完成,但是那些重复现有ID且尚未完成的ID的动作将取消先前的请求并取而代之。
例如:
1 2 3 4 5 6 7 | 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' |
我尝试使用
1 2 3 4 5 6 7 8 9 | 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'), )) |
目前,我正在使用
干杯!
编辑:我想知道将
例如
1 2 3 4 5 6 7 8 9 10 11 12 | 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:显然
Edit3:我认为这是我最终的工作版本。删除了mergeMap中Redux动作的解构,以防万一有人对redux-observables感到陌生:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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行为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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'), )) ) ); |