Back to the homepage

Get To Know The DestroyRef!

DestroyRef has been introduced in Angular 16 (commit link). It gives us the option to run a callback function when the component/directive is destroyed or when the corresponding injector is destroyed.

Let’s see an easy example to understand how we can use that.

Callback when a component is being destroyed

The code above emits a new value every 1 sec (1000ms) and logs a value to the console. It’s a small piece of code, but it still creates a memory leak since we are not destroying the subscription.

Let’s answer some questions you may have.

Q: What would happen if we changed the route?

A: Well, the component would be destroyed.


Q: What would happen if we came back to this route?

A: Well, the component would be constructed again.

Despite the component being destroyed, the subscription remains active.

We have to unsubscribe the subscription to avoid creating a memory leak. But perhaps you are already doing this ​👍

Let’s do the same, but this time using DestroyRef

Let’s read the code from top to bottom.

  • ​We are creating a #destroyRef instance using the inject method. Please note that this is happening during the injection context.
  • We are registering a callback function in the onDestroy method. The given function will be executed when the component is being destroyed.

Alternatively, we could write the same piece of code like that:

Note: This time, we are using the inject function in the constructor. This still works fine since we are in the injection context.

There is a better way to unsubscribe, though. Keep reading 🙂

Before we look at a better way to unsubscribe, let’s dig into some important details.

I have created the method myTakeUntilDestroyed, which injects DestroyRef.

It’s important to understand that we cannot use the inject method outside the injection context. 

In the example above, I call myTakeUntilDestroyed from the constructor, which works fine.

Injection Context: Constructor, class fields, factory method. Read more

What would happen if we call the method from the ngOnInit hook?

Since we are not in the injection context, Angular will throw an error.

If we, however, have to call myTakeUntilDestroyed from the ngOnInit hook, we should change how we access DestroyRef.

This change allows the developer to use myTakeUntilDestroyed outside of the injection context. As such, the code will become:

So far, we have covered some important details, and we are now ready to start using the takeUntilDestroyed rxjs operator.

takeUntilDestroyed completes the observable when the component/directive is destroyed or when the corresponding injector is destroyed!

That’s great! We have achieved the same with less and easy-to-read code. Nice!

Oh, wait, how about the ngOnInit hook?

If we have to use the takeUntilDestroyed operator outside the injection context, we (the developers) are responsible for providing DestroyRef, similar as in our custom myTakeUntilDestroyed method.

If you enjoy watching videos, you must take a look at this one that covers the same content as the article 

Get To Know the Angular DestroyRef

Useful links:

Thanks for reading my article!

About the author

Fanis Prodromou

I am a full-stack web developer with a passion for Angular and NodeJs. I live in Athens-Greece, and I have worked in many big companies. During my 14 years of coding, I have developed vast experience in code quality, application architecture, and application performance. Being aware of how rapidly computer science and the tech aspects evolve, I try to stay up to date by attending conferences and meetups, by studying and trying new technologies. I love sharing my knowledge and help other developers. "Sharing is Caring" I teach Angular in enterprise companies via Code.Hub institute, I write articles and create YouTube videos.

Don’t miss anything! Subscribe to our newsletter. Stay up-to-date with the latest trends, tips, meetups, courses and be a part of a thriving community. The job market appreciates community members.

Leave a Reply

Your email address will not be published. Required fields are marked *