takeUntilDestroy in Angular v16

Post Editor

takeUntilDestroy is a new feature coming in Angular 16. In this article, we will explore how it works, and learn how to use it.

2 min read
0 comments
post

takeUntilDestroy in Angular v16

takeUntilDestroy is a new feature coming in Angular 16. In this article, we will explore how it works, and learn how to use it.

post
post
2 min read
0 comments
0 comments

When subscribing to observables (especially in our components) we have to unsubscribe on destroy to prevent any memory leaks in our application. We can do it in a few ways, and now a new sheriff is in town! In most cases, it is probably the easiest to use since it does many things automatically.

Previous methods of unsubscribing from subscriptions added a lot of boilerplate to our classes, which reduced readability. For example, consider the following subscription that needs to be safely handled:

<>Copy
export class Component implements OnInit { data; ngOnInit(): void { this.service.getData().subscribe( response => this.data = response. ) } }

We could use takeUntil operator with additional subject:

<>Copy
export class Component implements OnInit, OnDestroy { data; destroyed = new Subject() ngOnInit(): void { this.service.getData() .pipe( takeUntil(this.destroyed), ) .subscribe( response => this.data = response ) } ngOnDestroy(): void { this.destroyed.next(); this.destroyed.complete(); } }

Or any other method to deal with an open subscription — there is many of them, but as long as you are calling the subscribe in the component’s class you will end up with many boilerplate code.

Luckily that’s when new operator comes into play in Angular 16 — the takeUntilDestroy. This pipe-able operator functions similarly to the example above with takeUntil(this.destroyed), but with almost zero additional code required!

Injectable OnDestroy
Link to this section

Angular 16 introduced a flexible ngOnDestroy, which makes the OnDestroy hook injectable.

<>Copy
destroyRef = inject(DestroyRef);

This allows us to inject it into our components instead of using it as a method. As a result, we can modify our takeUntilexample to something like this:

<>Copy
export class Component implements OnInit { destroyRef = inject(DestroyRef); ngOnInit(): void { const destroyed = new Subject(); this.destroyRef.onDestroy(() => { destroyed.next(); destroyed.complete(); }); this.service.getData() .pipe(takeUntil(destroyed)) .subscribe(response => this.data = response) } }

This basically means that we don't need to implement the ngOnDestroy method in our component. All the "additional" code can be wrapped within a pipe-able operator, which is what happened!

takeUntilDestroy
Link to this section

Now we can use the takeUntilDestroy operator, which is super convenient. Just add it to the pipe without passing anything, and it will automatically pick up the right OnDestroy for the current context — using injectable OnDestroy.

<>Copy
import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; export class Component implements OnInit{ data; constructor(private service: DataService) { this.service.getData() .pipe(takeUntilDestroyed()) .subscribe(response => this.data = response) } }

That is all!

Passing OnDestroy reference
Link to this section

In some cases, we may want to react to the destroy event of another component. For example, consider a scenario where a parent component has a subscription that needs to remain active as long as the child component is on the screen. In this case, we can inject DestroyRef in the child component:

<>Copy
export class Child { destroyRef = inject(DestroyRef); }

We can use the new takeUntilDestroyed operator in the parent component to close the subscription by passing the reference to the DestroyRef of the child component. Here is an example implementation for the parent component:

<>Copy
export class Parent { @ViewChild(Child) child: Child; ngOnInit(): void { interval(1000) .pipe(takeUntilDestroyed(this.child.destroyRef)) .subscribe((count) => console.log(count)); } }

The count will be logged to the console as long as the Child component exists. Upon its destruction, the subscription in the Parent will be stopped.

Have fun and enjoy Angular 16 features! 🤓

Comments (0)

Be the first to leave a comment

Share

About the author

author_image

Hey, I'm a frontend developer, passionate about good design for both the code and UX/UI side of things. I am mainly involved in Angular, rxjs, typescript subjects.

author_image

About the author

Maciej Wojcik

Hey, I'm a frontend developer, passionate about good design for both the code and UX/UI side of things. I am mainly involved in Angular, rxjs, typescript subjects.

About the author

author_image

Hey, I'm a frontend developer, passionate about good design for both the code and UX/UI side of things. I am mainly involved in Angular, rxjs, typescript subjects.

Featured articles