In this post we are going to discuss what is switchmap operator, how do we use this operator to do proper synchronization, how does it differs from other operators such as map and mergeMap. Without further ado, lets dive in.
Let's define what does switchMap does, simply defined from official documentation "Map to observable, complete previous inner observable, emit values"
Synchronization
Examples of simple requirements that switchMap would be applicable are as follows:
- When something triggers I need to call this second Observable.
// ID Type alias.
type ID = string
// Define a trigger to call the API.
const loadMyData$ = new Subject<ID>();
// Data upon trigger.
const data$ = loadMyData$.pipe(
switchMap(id => httpGetData(id)) // API request
);
// Some trigger happens
loadMyData$.next("10d27de0-...-62b02cd72468") // trigger to get http data.
Whenever we use switchMap we are passing our task to other Observable. Its like saying to your friend, "Hey I did my part and this is what I produce, now do yours". In our example, we we're passing our trigger to httpGetData API request.
What if I my trigger is so fast, I don't want to overload my server with API requests?"
In the next example, we explore cancellation, using switchMap.
And now for the special part of switchMap, cancellation or unsubscription of inner Observable.
switchMap has the ability to cancel or unsubscribe inner observable, in our case the API request could take time to complete for example, fetching a large BLOB or any expensive API requests, we don't want to flood our API with useless requests, scenarios like:
- When I trigger multiple API calls, I want my previous API calls to be cancelled.
// Next Image Trigger.
const nextImage$ = new Subject<ID>();
// Get image.
const data$ = nextImage$.pipe(
switchMap(id => httpGetImage(id)) // supports cancellation internally.
);
No special wiring of Observable, it's basically the same as the first example.
When not to use switchMap
There are other alternative operators for passing or switching Observable, mergeMap would be an example, the only difference is mergeMap does not have cancellation on internal. This is useful for example add item to the cart, when calling the API, it may not be useful if we use switchMap, but make sure to check your requirements first.
Difference from map operator
map only transform values, and not needing the task to another Observable, for example:
const date$ = dateTrigger$.pipe(
map(stringDate => new Date(stringDate))
);
// Should be equal to
const date$ = dateTrigger$.pipe(
switchMap(stringDate => of(new Date(stringDate)))
);
Why not use concat after the trigger?
concat awaits for the first Observable to complete before triggering the second Observable, in many cases there can be no completion of the source Observable, thus leaving the second Observable not to be called at all.
Personal Preference
When faced with uncertainty, I'd like to use switchMap first to stitch Observable together specially on calling APIs whether the source is interval, or manual click trigger, only then after that I'll assess the synchronization requirements.
Bonus
The signature resembles to monad operator bind.
Thank you for reading this far, let me know what you think below.
Top comments (0)