So I have use case where I update the api request when the map is moved - but it could generate several rapid fire requests with small map movements - and I want to cancel all the inflight requests except for the last one. I can use debounce to only send requests after a delay. However I still want to cancel any old requests if they happen to still be in process.
const fetchNearbyStoresEpic = action$ =>
action$.ofType(FETCH_NEARBY_STORES)
.debounceTime(500)
.switchMap(action =>
db.collection('stores')
.where('location', '<=', action.payload.max).
.where('location', '>=', action.payload.min)
.map(response => fetchNearbyStoresFulfilled(response))
.takeUntil(action$.ofType(FETCH_STORES_CANCELLED))
);
I see that you can use takeUntil
but you need to explicitly fire a cancel action. I see in the docs that switchMap will take the latest and cancel all the others - do I have to implement a cancel interface in my api call? In this case it would be a firebase query to firestore.
switchMap
will abandon its previous observable when a new emission is send through it. Depending on your underlying HTTP library and if it supports cancellation (Observable aware) this should suffice.Because no implementation details have been provided in your question you will have to look into
fetchNearbyStoresFulfilled
to see if it uses an Observable aware http client. If it internally is using promises then no cancellation support is provided.From a comment I made in a GitHub issue:
So, like Mark said in his answer, when
switchMap
receives a subsequent action, it will unsubscribe from any incomplete request.However, the request won't be cancelled until the debounced action makes it to the
switchMap
. If you want to cancel any pending requests immediately upon another move - rather than wait for the debounce duration - you can usetakeUntil
with theFETCH_NEARBY_STORES
action:That should effect the immediate unsubscription from a request upon another move. (Off the top of my head, I cannot recall the behaviour of
action$
inredux-observable
. It's possible that you might need to append askip(1)
to the observable passed totakeUntil
. Try it and see.)And, as Mark mentioned, this is predicated on the underlying implementation cancelling the request upon unsubscription.