RXJS: assigning and then reusing value between operators

Viewed 59

Suppose I have a function GetUserRecommendedSongs. It does the following:

  1. It presents the user with a dialog: what is your mood today? (happy\gloomy\nostalgic)
  2. Using the result it calls a service GetUserRecommendationsByMood.
  3. It then returns a result for example: {mood: "nostalgic", songIds: [12, 25]};
  4. The caller of this function (possibly several ui components) would use the result to play the songs under the title "so you feel ${result.mood} today?"

The problem is I use the mood twice: to get the recommendations, and in the final result.

With async\await I would do:

const requiredMood = await ShowRequiredMoodDialog();
//handle cancellation e.g. if(!mood)
let recommendedSongs = await GetUserRecommendations(mood);
return {mood, recommendedSongs};

However with rxjs I was only able to come up with the following:

let mood$ = ShowRequiredMoodDialog().pipe(share) //has to be shared so we don't show the dialog twice
let recommendedSongs$ = mood$.pipe(switchMap((mood)=> GetUserRecommendations(mood)));
return forkJoin(mood$, recommendedSongs$) //with some selector\map to turn into object

(note to reader: don't use this as a reference to rxjs, as I did not test this code)

This code is quite complicated. Can it be simplified?

2 Answers

The only different way that comes to my mind is like this but I don't know which one is more readable:

mood$.pipe(
  switchMap(mood => GetUserRecommendations(mood).pipe(
    map(recommendedSongs => [mood, recommendedSongs]),
  ),
)

What about this one?

let mood$ = ShowRequiredMoodDialog().pipe(share());
let recommend = (mood) => {
  return { mood, songs: GetUserRecommendations(mood) };
};
let recommendedSongs$ = mood$.pipe(switchMap(recommend));
return recommendedSongs$;
Related