86

I find many examples where ActivatedRoute Observables like params or url are subscribed but not unsubscribed.

constructor(private route: ActivatedRoute) {}

ngOnInit() {
  this.route.params
    // (+) converts string 'id' to a number
    .switchMap((params: Params) => this.service.getHero(+params['id']))
    .subscribe((hero: Hero) => this.hero = hero);
}
  • Are the route objects and subscriptions destroyed automagically and newly created for every component creation?
  • Do I have to care about unsubscribing from those Observables?
  • If not, can you explain what happens with the tree of ActivatedRoute objects in Router.routerState?
hgoebl
  • 11,224
  • 7
  • 39
  • 67
  • No need to unsubscribe any router params. You will only need unsubscribe if you have created in component level. – kk4You Jun 27 '20 at 08:02
  • Yes, you need, I've had times where my component is destroyed and then the `queryParams` subscription triggers one last time after that. – Daniel Feb 04 '21 at 15:54

5 Answers5

176

From the docs :

When subscribing to an observable in a component, you almost always arrange to unsubscribe when the component is destroyed.

There are a few exceptional observables where this is not necessary. The ActivatedRoute observables are among the exceptions.

The ActivatedRoute and its observables are insulated from the Router itself. The Router destroys a routed component when it is no longer needed and the injected ActivatedRoute dies with it.

Feel free to unsubscribe anyway. It is harmless and never a bad practice.

Sébastien
  • 10,675
  • 11
  • 47
  • 67
Milad
  • 22,895
  • 9
  • 62
  • 76
  • 4
    How do you unsubscribe since it is "never a bad practice". Docs give no examples at all of unsubscribing – TetraDev Aug 23 '17 at 22:12
  • 10
    @TetraDev Like this.. ngOnInit() { this.routeSub = this.route.paramMap .subscribe(params => { this.event = this.eventService.getEvent(+params.get('id')); }); } ngOnDestroy() { this.routeSub.unsubscribe(); } – DJDJ Oct 11 '17 at 08:40
  • how do you `unsubscribe` if you are subscribing to `ActivatedRoute` in `app.component`? – candidJ Sep 24 '18 at 08:58
  • @candidJ you can unsubscribe in the same fashion as @DJDJ described, but since `app.component` will live as long as app lives, there is no real need to unsubscribe there anyway. – crollywood Aug 29 '19 at 11:57
  • Hi @Milad - can you pls point me to a source where I could find ALL the exceptions from the rule 'having to unsubscribe'? Thank you. – PaxForce Jan 14 '20 at 14:49
  • @PaxForce not sure if there's a source, however, anything created by Angular team itself doesn't need to be unsubscribed ( as far as I can rememeber). Like route events, HTTP events, mouse and keyboard events, etc. Anything that you create yourself , like myevent = new EventEmitter() ... or myevent = new Subject(), needs needs you to unsubscribe ( technically, it all depends on the nature of the event , but what I said is a rule of thumb). What I suggest is, always, always unsubscribe, so you know exactly what's going on – Milad Jan 15 '20 at 15:17
  • 1
    I updated the documentation link in this answer, but note that the "Feel free to unsubscribe anyway. It is harmless and never a bad practice." sentence is no longer in the documentation. – Sébastien Jun 27 '20 at 07:48
  • I just found a bug in my code caused by a queryParams subscription triggering one last time after ngOnDestroy was called. So, to play safe I'm unsubscribing even from ActivatedRoute observables now. – Daniel Feb 04 '21 at 15:56
7

The component will be destroyed and the routerState will become unreferenced when the router navigates to a different route, which will make them free to get garbage collected including the observable.

If you pass around references to this component to other components or services, the component won't be garbage collected and the subscription would be kept active, but I'm sure (without verifying) that the observable will be completed by the router when navigating away and cause the subscription to cancel.

Günter Zöchbauer
  • 490,478
  • 163
  • 1,733
  • 1,404
  • 1
    This means that `ActivatedRoute` is a new instance after every route navigation, right? How would then work the subscription to changed route params? Maybe you could explain the special lifecycle of `ActivatedRoute`? Is the `RouterState` tree recreated from root after every navigation? If the component is destroyed after navigation, this would cause flickering!? – hgoebl Dec 27 '16 at 15:06
  • 2
    If you navigate to a different route, then the component is destroyed, if you navigate back it is recreated. If you have the same component on different routes and you navigate from one to the other the component is also destroyed and recreated. Only when you navigate, so that only route parameter(s) change, then the component instance is reused. Recent versions support a custom reuse strategy. See also https://github.com/angular/angular/issues/7757#issuecomment-236737846 and https://www.softwarearchitekt.at/post/2016/12/02/sticky-routes-in-angular-2-3-with-routereusestrategy.aspx – Günter Zöchbauer Dec 27 '16 at 15:10
  • Thanks Zöchi for your answer. I was not sure who will get the bounty, but Milad has only 1 point reputation, while you have already 149k. BTW his answer proves by citing official docs. Next time, very soon, you'll be the man again :-) – hgoebl Jan 02 '17 at 11:54
  • No worries. Happy new year :) – Günter Zöchbauer Jan 02 '17 at 11:55
6

As the winning answer quotes about the subscriptions to ActivatedRoute, Angular unsubscribes automatically.

The Router destroys a routed component when it is no longer needed and the injected ActivatedRoute dies with it.

In case you want to know how to unsubscribe from Observables:

import { Component, 
         OnInit,
         OnDestroy }      from '@angular/core';
import { ActivatedRoute } from '@angular/router'; 
// Type
import { Subscription } from 'rxjs/Subscription';


@Component({
  selector: 'app-example',
  templateUrl: './example.component.html',
  styleUrls: ['./example.component.scss']
})
export class ExampleComponent implements OnInit, OnDestroy {
  paramsSubscription : Subscription;

  constructor(private activatedRoute : ActivatedRoute) { }

  /* Angular lifecycle hooks
  */
  ngOnInit() {
    console.log("Component initialized");
    this.paramsSubscription = this.activatedRoute.params.subscribe( params => {

    });
  }

  ngOnDestroy() {
    console.log("Component will be destroyed");
    this.paramsSubscription.unsubscribe();
  }

}
Marian07
  • 1,414
  • 3
  • 23
  • 38
1

Whenever you are adding subscribe to a component, you always almost need to unsubscribe when the component is getting destroyed. But subscribe to the Activated route params doesn't require to unsubscribe as the router destroys the subscribe whenever its no longer needed.

thegautamnayak
  • 210
  • 2
  • 12
0

Http observables calls and router observables dont need to unsubscribe manually. In case you handle other kind of observbable or your own observable you should do it on ngOnDestroy(). You do it calling unsubscribe() method inside Suscription object where you storage your observable in the component.

Yair Abad
  • 140
  • 2
  • 5