It depends on what you do in your subscription, whether you should unsubscribe or not. A best practice that has been used by myself in many projects was
- In general: Don't unsubscribe when using
HttpClient
. It is only necessary when you have logic affecting global application state in the subscription because it eventually completes. - Everywhere else: Pipe the observable and use
takeUntilDestroyed
. Although it is not necessary in some cases, it prevents forgetting it somewhere.
See Unsubscription methods for the possibilities for unsubscription and details how to correctly unsubscribe.
See Examples for info on how to run the example Angular app, where you can verify the findings yourself and where the different unsubscription methods can be tried.
There's a lot of confusion in the community about the question if and when you have to unsubscribe manually from RxJS observables in Angular components.
Although there are some quite nice StackOverflow posts about this question, there is no clear guide that contains all relevant information explained by examples.
Our guide focuses on issues with components using observables.
A typical component lifecycle in an Angular CRUD application contains the following steps (simplified version):
- User navigates to component
A
- Component
A
gets initialized (constructor andngOnInit
are invoked) - Some logic is called to load data (e.g. using
HttpClient
).
Subscriptions to observables are made. - User navigates to another component
B
- Component
A
gets destroyed (ngOnDestroy
is invoked) - ...
This repository provides a guide explaining when you have to unsubscribe manually from subscriptions
(when component A
gets destroyed).
Whether you have to unsubscribe or not depends on the callback logic you are using in the observables' subscription.
If the callback logic from the subscription executes code with side effects (affecting global application state) you should always consider to manually unsubscribe when the component gets destroyed. Otherwise, the current and correct application state can be falsely overwritten by callback execution from an already destroyed component.
If the subscription callback from an observables that does not eventually complete uses member variables from the component, the destroyed component cannot be garbage collected, thus resulting in a memory leak. Therefore, you should always unsubscribe in that case.
Even if not using a components variable in the callback, observables that don't eventually complete (for example an observable emitting a value each second) should be cancelled always, since the callback logic from the destroyed component still runs (infinitely) in the background otherwise.
The Angular HttpClient
creates an observable that eventually completes. Therefore it is prone to unwanted side effects
but not to memory leaks.
For observables from the ActivatedRoute
you do not have to unsubscribe manually.
From the official Angular docs:
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.
For Angular Router events (NavigationStart
, NavigationEnd
, ...) , i.e.
constructor(private router: Router) {
this.router.events.subscribe((event) => {
// some logic
});
}
you may have to manually unsubscribe.
When you should unsubscribe when the component gets destroyed.
Side effects | Memory leaks | Should unsubscribe | |
---|---|---|---|
Observables that don't complete | Possible (1) | Possible (2) | Yes |
Observables that eventually complete | Possible (1) | No (3) | Depends (1) |
Angular HttpClient | Possible (1) | No (3) | Depends (1) |
Angular ActivatedRoute | No | No | No (4) |
Angular Router events | Possible (1) | Possible (2) | Yes |
(1): If you execute methods with side effects in the subscription callback.
(2): If you use member variables from the component in the subscription callback.
(3): Assuming the observable completes.
(4): You don't have to, but are free to unsubscribe anyway.