Reputation: 476
Following the best practices as described in this Stack Overflow post: Angular RxJS When Should I Unsubscribe From Subscription, consider this Angular component lifecycle hook:
private ngUnsubscribe: Subject<void> = new Subject();
ngOnInit() {
this.fireAuth.authState
.takeUntil(this.ngUnsubscribe)
.mergeMap((user) => this.todoService.getUserTodos(user.uid))
.takeUntil(this.ngUnsubscribe)
.subscribe((todos) => this.userTodoArray = todos);
}
ngOnDestroy() {
this.ngUnsubscribe.next();
this.ngUnsubscribe.complete();
}
As authState()
and mergeMap()
both return Observables, I think I'm supposed to either
takeUntil()
operators, either from the outer Observable authState()
or the inner Observable this.todoService.getUserTodos(user.uid)
.Which method is correct to make sure all Observables are unsubscribed after the component is destroyed?
Upvotes: 3
Views: 4867
Reputation: 58430
You don't need both of the takeUntil
operators. You only need one, but the behaviour will differ depending upon which one you remove.
If you use only the first takeUntil
, like this:
this.fireAuth.authState
.takeUntil(this.ngUnsubscribe)
.mergeMap((user) => this.todoService.getUserTodos(user.uid))
.subscribe((todos) => this.userTodoArray = todos);
When this.ngUnsubscribe
emits a next
notification, the takeUntil
will unsubscribe from the this.fireAuth.authState
source and will complete. As outlined in the Observable Contract, when an observable completes, its subscribers receive a complete
notification and are automatically unsubscribed.
However, if a next
notification was emitted from this.fireAuth.authState
and the observable returned by getUserTodos
in the mergeMap
has not yet completed, the mergeMap
implementation will not unsubscribe from the getUserTodos
observable. And if the getUserTodos
observable later emits a next
notification, the notification will flow through to the subscribe
.
If you use only the second takeUntil
, like this:
this.fireAuth.authState
.mergeMap((user) => this.todoService.getUserTodos(user.uid))
.takeUntil(this.ngUnsubscribe)
.subscribe((todos) => this.userTodoArray = todos);
When this.ngUnsubscribe
emits a next
notification, the takeUntil
will unsubscribe from the mergeMap
, which will unsubscribe from this.fireAuth.authState
and from any returned getUserTodos
observable.
So, after this.ngUnsubscribe
emits, no notifications will flow through to the subscribe
. It's likely that this is the behaviour you are looking for, so you should remove the first takeUntil
operator.
Upvotes: 18