Reputation: 11599
I use the following code in an angular app. I used the RxJS map
call similar to how array map
is used. After reading about RxJS switchmap
operator, I'm not sure whether I should use map
or switchmap
. Should I use switchmap
so the observable which is returned from the http
call is closed so there is no memory leak?
getPeopleForTypeahead(term: string): Observable<IPersonForTypeahead[]> {
var peopleUrl = `https://localhost:5001/api/peoplesearch?name=${term}`;
return this.http.get<any>(peopleUrl)
.pipe(
map(pl => {
return this.peopleAsFlattened(pl.peopleList).reduce((p, c) => p.concat(c));
}),
catchError(this.handleError('getPeopleForTypeahead', []))
);
}
peopleAsFlattened = (pla: IPeopleList[]) => {
return pla.map(pl => pl.people.map(p => {
return {
id: p.id,
fullName: p.fullNames[0].firstName + " " + p.fullNames[0].lastName
};
}));
}
Upvotes: 2
Views: 13716
Reputation: 14750
map
and switchMap
have completely different purposes:
map
- transform the shape of an emissionswitchMap
- subscribe to an observable and emit its emissions into the streammap
Use map
when you want transform the shape of each emission. Ex: emit the user name property, instead of the entire user object:
userName$: Observable<string> = this.service.getUser(123).pipe(
map(user => user.name)
);
switchMap
Use switchMap
when you want to map an emission to another observable and emit its emissions. Ex: You have an observable of some id
and want to emit the resource after fetching it:
user$: Observable<User> = this.userId$.pipe(
switchMap(id => this.service.getUser(id)),
);
When user$
is subscribed to, the user returned from service.getUser(id)
is emitted (not the userId string).
Upvotes: 8
Reputation: 831
switchMap
is not interchangeable with the map
operator, nor vise versa. Although both of them has to do with mapping (as their names suggest), they have two separate use-cases.
In your particular case, the map
operator is the way to go.
switchMap
?You can only use switchMap(cb)
when you check all these requirements:
Your callback function, cb
, passed into switchMap
returns an observable, observable$
.
If your cb
(callback function) does not return an observable, you should look into operators that don't handle higher-level observables, such as filter
and map
(what you actually needed); not operators that handle higher-level observables such as concatMap
and well, switchMap
.
You want to execute your cb
sequentially before the next operation down the pipeline (after switchMap
) executes.
Maybe you want to run logic inside of cb
, and optionally get the return value of cb
after executing, so that you can pass it down the pipeline for further processing, for example.
When you want to "discard" what will happen to cb
's execution and re-execute cb
every time the source observable (the thing that trickles down to switchMap(cb)
) emits a new value/notification.
Applying what we hopefully learned, we know that your cb
:
pl => {
return this.peopleAsFlattened(pl.peopleList).reduce((p, c) => p.concat(c));
}
returns a plain JavaScript array; not an observable. This takes using switchMap
out of the question since it violates the first requirement I made up above.
Hopefully that makes sense. :)
Upvotes: 2
Reputation: 11360
We use switchMap
when the source observable is a hot observable. In which case you prefer the behaviour that cancel the succeeding observable when source emits.
In your code, you source is a one-off http call which means it will not emit multiple times and the follow up action is not executing observable but to mutate an array. There is no need to use switchMap
Upvotes: 0