DEV Community

Gérôme Grignon
Gérôme Grignon

Posted on

Understanding takeUntilDestroyed in Angular

Angular applications often rely on Observables for handling asynchronous operations, such as HTTP requests, user events, or real-time data streams. Managing the lifecycle of these subscriptions is crucial to prevent memory leaks and unexpected behavior, especially as components and services are created and destroyed.

One of the most effective tools for this in modern Angular is the takeUntilDestroyed operator, introduced in the @angular/core/rxjs-interop package.

What is takeUntilDestroyed?

Angular takeUntilDestroyed compatibility

takeUntilDestroyed is an RxJS operator that automatically completes an Observable when the calling context (such as a component, directive, or service) is destroyed. This means you no longer need to manually unsubscribe from Observables in your ngOnDestroy lifecycle hook, takeUntilDestroyed handles it for you.

import { takeUntilDestroyed } from '@angular/core/rxjs-interop';

@Component({...})
export class MyComponent {
  private someService = inject(SomeService);
  constructor() {
    this.someService.getData()
      .pipe(takeUntilDestroyed())
      .subscribe(data => {
        // handle data
      });
  }
}
Enter fullscreen mode Exit fullscreen mode

When the component is destroyed, the subscription is automatically cleaned up, preventing memory leaks and side effects from lingering subscriptions. This is especially important for Observables that emit multiple values over time, such as those from interval, Subject, or real-time data sources, as opposed to HTTP requests with HttpClient, which complete automatically after a single emission.

It does not mean you should not care about the unsubscription of HTTP Requests: Letting them live after the component destruction could lead to some side effects you want to avoid.

Usage outside of the injection content

If you need to use it outside of an injection context, you can inject a DestroyRef and pass it explicitly:

import { DestroyRef, inject } from '@angular/core';

export class MyComponent {
  private someService = inject(SomeService);
  private destroyRef = inject(DestroyRef);

  getData() {
    this.someService.getData()
      .pipe(takeUntilDestroyed(this.destroyRef))
      .subscribe();
  }
}
Enter fullscreen mode Exit fullscreen mode

Best practices

When data from your observable is meant to be used only in a template, prefer relying on the async pipe to subscribe. Angular will automatically clean the subscription when the component is destroyed.

Top comments (0)