简体   繁体   中英

What to use instead of subscribe() for an Observable

I'd like to close a login dialog whenever the Firebase authState changes. I read online that I the subscribe() function would cause data leaks if the unsubscribe() function isn't called and therefore, want to replace the function. Here is my code:

this.user = this.auth.authState.pipe(
  switchMap( (user) => {
    if(user) {
      return (this.firestore.collection('users').doc(user.uid).valueChanges() as Observable<User>)
    } else {
      return of(null);
    }
  })
);

I'd like to replace the subscribe function here with something else:

this.authService.user.subscribe( (user) => {
  if(user) {
    this.isLoading = false;
    this.dialogRef.close();
  }
})

This is what I tried, but I think I'm using the map function incorrectly:

this.authService.user.pipe(
  map( (user) => {
    if(user) {
      this.isLoading = false;
      this.dialogRef.close();
    }
  })
)

Thanks in advance!

The subscribe function in itself is not bad, or any memory leak. It becomes an issue when you do not unsubscribe the Subscription or complete the Observable when the component code or service code is destroyed.

But it all depends on what you want to do:

If this is a global listener in a root service. You do not have to care about it, because the life cycle of the service is the same as your entire app.

If it's a listener in a component, you need to make sure to unsubscribe from it when the component is destroyed:

@Component({...})
export class SomeComponent implements OnDestroy {
  private destroy$ = new Subject<void>();

  constructor(private authService: AuthService) {}

  checkLogin(): void {
    this.authService.user.pipe(
      filter((user) => !!user),
      takeUntil(this.destroy$)
    ).subscribe((user) => {
      this.isLoading = false;
      this.dialogRef.close();
    });
  }

  ngOnDestroy(): void {
    this.destroy$.next();
    this.destroy$.complete();
  }
}

Judging by your code it feels like you are using angular material as well, and you are actually waiting for a user to login. Then this would be the most appropriate solution:

@Component({...})
export class SomeComponent {
  constructor(private authService: AuthService) {}

  checkLogin(): void {
    this.authService.user.pipe(
      filter((user) => !!user),
      take(1),
      takeUntil(this.dialogRef.beforeClosed)
    ).subscribe((user) => {
      this.isLoading = false;
      this.dialogRef.close();
    });
  }
}

This unsubscribes when:

  • the dialog is closed by using takeUntil(...)
  • after the first emit of the AuthService with a user by using filter(...) and take(1)

And only in the second case will it reach the subscribed method

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM