I'm working in a project with Angular using NgRx to manipulate the state with actions and reducers. A common code I see around here uses to call a subscribe inside a subscribe (which I know is generally wrong, but I don't understand why since it works). This question perfectly explains how to deal with this problem, but my case - I think - is slightly different since I need to grab a piece of the NgRx store first.
What I am currently doing is the following:
this.store.pipe(
take(1),
select(userProfile) // <-- take data from the NgRx store
).subscribe(currentUser => {
this.loggedUser = currentUser;
this.achievementService.getAchievement(
(achievment: Achievement) =>
achievement.id === currentUser.achId
).subscribe(
response => {
// ... more code
this.categoryService.getCategory(response.id).subscribe(
category=> {
// ... more code
}
);
}
);
As you can see I need to use the result of each subscribe in the next one but first I need to get a piece of the NgRx store. How would you refactor this portion of code so that it won't use multiple Observable.subscribes? And also, can you explain me the potential issues that might rise when calling a subscribe inside another?
Solution
The solution proposed by @ngfelixl works, but I want to take some time to specify a couple of things before accepting it. First, if you have multiple lines of code in a switchMap you have to explicitly return the observable:
switchMap(currentUser => {
this.loggedUser = currentUser;
return this.achievementService.getAchievement(
(achievment: Achievement) =>
achievement.id === currentUser.achId
);
})
Second, you still need a final subscription (which is the only subscription you will use). Here is the complete code sample:
this.store.pipe(select(userProfile)).pipe(
switchMap(currentUser => {
this.loggedUser = currentUser;
return this.achievementService.getAchievement(...);
}),
switchMap(achievement => this.categoryService.getCategory(achievement.id))
).subscribe(category => ...)