Maurice
Maurice

Reputation: 7381

Observable subscription remains active after component has been destroyed

One of my components subscribes to router events like so:

    this.navigationSubscription = this.router.events.subscribe((e: any) => {
      // If it is a NavigationEnd event re-initalise the component
      if (e instanceof NavigationEnd) {
        let p = e as NavigationEnd;
          console.log(p.urlAfterRedirects);
        console.log("im being called from NavigationEnd");
        this.ngOnInit();
      }
    });
   }

I use this code to reload the component when the user navigates to the component a second time via a button. While debugging a problem i noticed that when i navigate to another component this piece of code still remains active even though the component that its part of is not. Can someone explain why and how this code stays active even though the component itself is no longer there? Shouldn't the code cause an error when it can no longer reach this.ngOnInit() ?

I can solve this problem by unsubscribing to it in the onDestroy method but i would really like to know how the code is able to stay active when the component is no longer there, and why this.ngOnInit() doesn't throw an error since the component is not active.

Upvotes: 5

Views: 7405

Answers (3)

Bytech
Bytech

Reputation: 1215

A physical world example, and how I understand subscriptions: if I subscribe to a newspaper to my street address, and my house gets destroyed by (insert bad scenario), I still have to cancel the subscription, otherwise the newspapers will pile up on the burned heap of what used to be my home.

Upvotes: 5

danday74
danday74

Reputation: 57036

Generally speaking, all subscriptions remain active after the component is destroyed.

It is one of the big pains of Angular IMO.

However, there are some exceptions to this rule:

  • this.activatedRoute.params.subscribe - automatically unsubscribes
  • this.activatedRoute.data.subscribe - automatically unsubscribes
  • any http subscriptions - these will emit once and then complete, so no need to unsub
  • async pipes unsub automatically

For everything else you need to unsub manually. There are various ways of doing this but here is the RxJs recommended approach:

private unsubscribe$ = new Subject()

this.someobservable.pipe(
  takeUntil(this.unsubscribe$)
).subscribe( .... )

ngOnDestroy() {
  this.unsubscribe$.next()
  this.unsubscribe$.complete()
}

Upvotes: 7

Jota.Toledo
Jota.Toledo

Reputation: 28434

Can someone explain why and how this code stays active even though the component itself is no longer there?

Although the component is "no longer there", this only means that the pointer to the Subscription instance stored in it is gone, but the subscription is still 'active', and most likely tracked by the router.events stream, explaining why the GC cant simply remove the instance from memory.

Shouldn't the code cause an error when it can no longer reach this.ngOnInit() ?

Most likely related to the first point, as the GC cant release the component instance.

Upvotes: 1

Related Questions