Nested exhaustMap and concatMap for Firebase Authentication RxJs

Viewed 114

I'm trying to implement Firebase Authentication and sending received user's data to the server for creating account in my app.

Here is the code:

  ngAfterViewInit(): void {
    const provider = new firebase.auth.GoogleAuthProvider();
    fromEvent(this.LoginWithGoogle.nativeElement, 'click')
      .pipe(
         exhaustMap(() =>
           from(this.afAuth.signInWithPopup(provider)).pipe(
              map((data) => data.user),
              concatMap((user) =>
                this.authService.loginWithGoogle({
                   email: user.email,
                   username: user.displayName,
                })
              )
           )
         )
       )
       .subscribe((res) => {
           console.log(res);
       });
  }

It works well. But is it right to use nested RxJs operators like this? And there is any alternative solution for this case?

1 Answers

I think this would work:

ngAfterViewInit(): void {
  const provider = new firebase.auth.GoogleAuthProvider();
  
  fromEvent(this.LoginWithGoogle.nativeElement, 'click')
    .pipe(
        exhaustMap(() => from(this.afAuth.signInWithPopup(provider))),
        map((data) => data.user),
        concatMap((user) => this.authService.loginWithGoogle({ 
            email: user.email,
            username: user.displayName,
          })
        )
      )
      .subscribe((res) => {
          console.log(res);
      });
}

When you're using operators like switchMap, exhaustMap, mergeMap, concatMap, which handle inner observables automatically, you can simply imagine that instead of manually subscribing to that the callback returns, you let that job do be done by the operator. In addition to this, the value emitted by the inner observable is passed along to the outer observable(most of the times - the main stream). That's why I was able to use map on the save level as exhaustMap.

Edit

If you also want to handle errors in inner observables, you can use something like this:

exhaustMap(() => from(...).pipe(catchError(() => EMPTY)))
Related