DestroyRef: Your New Angular Friend
Angular v16 introduces DestroyRef, a new provider that simplifies your code by executing cleanup tasks before a scope is destroyed. This eliminates the need for inheritance and makes your code cleaner and easier to understand.
Angular has recently launched Angular v16, which includes several new features, including the highly anticipated DestroyRef provider.
Although features like hydration, required inputs, and new signals are significant, DestroyRef directly impacts many of us.
What Does Angular DestroyRef Do?
It enables the creation of common logic that executes some cleanup logic before a scope
gets destroyed.
Where scope
can be a component, directive, pipe, embedded view, or an instance of EnvironmentInjector
.
Here's how to use it:
@Component({ ... })
export class MyComponent {
constructor() {
inject(DestroyRef).onDestroy(() => {
// do something when the component gets destroyed
})
}
}
Well, it doesn't do so much you can say, but his role in an Angular application can be much more important than other features.
How DestroyRef Can Simplify The Code
Let's take a look at how we used to unsubscribe before Angular v16:
@Component({...})
export class MyComponent implements OnDestroy {
readonly onDestroyed$ = new Subject();
// Some Observable we have to unsubscribe from when component gets destroyed
readonly someObservable$ = unknownObservable$.pipe(takeUntil(this.onDestroy$)).subscribe()
ngOnDestroy() {
this.onDestroy$.next('')
this.onDestroy$.complete()
}
}
DestroyRef
is here to make this action much more straightforward.
We can create an rxjs onDestroyed
operator that relies on it:
export function onDestroyed() {
const subject = new Subject();
inject(DestroyRef).onDestroy(() => {
subject.next('');
subject.complete();
});
return () => takeUntil(subject.asObservable());
}
And change the component logic like this:
@Component({...})
export class MyComponent {
readonly someObservable$ = Observable;
readonly onDestroyed = onDestroyed()
constructor() {
this.someObservable$ = unknownObservable$.pipe(this.onDestroyed()).subscribe()
}
}
Looks much more simple, right? And the best part? You don't need to use inheritance!
Is the era of the 'ngOnDestroy' coming to an end?
Of course not, ngOndestroy
is there to be, it can be used for many other things but DestroyRef
is here to replace one of the most used logic we used to write within the ngOnDestroy lifecycle hook - the unsubscription from an observable!
Pretty neat, right? But what if I tell you we don't even need to create a custom onDestroyed
operator?
Angular Team took care of us and created takeUntilDestroyed
operator.
A Step Further, takeUntilDestroyed Operator
Angular 16 comes with a set of new functions from @angular/core/rxjs-interop
which are in the developer preview as part of the v16 release!
One of them is takeUntilDestroyed
operator.
takeUntilDestroyed
operator is a function similar we have written above - onDestroyed
.
So you don't need to write the same function again and again throughout all your Angular applications.
Let's take a look at how to implement takeUntilDestroyed
operator:
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
@Component({...})
export class MyComponent {
// Inside an Injection Context
constructor() {
unknownObservable$.pipe(takeUntilDestroyed()).subscribe();
}
}
You should know that DestoryRef
must be used inside an injection context, and takeUntilDestroyed
operator is not an exception.
In this example, Angular is able to use DestroyRef
under the hood, but if we want to use it outside the class' constructor
we have to pass it:
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
@Component({...})
export class MyComponent {
readonly destroyRef = inject(DestroyRef);
// Outside an Injection Context
ngOnInit() {
unknownObservable$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe();
}
}
Wrapping Up
In summary, Angular v16's new DestroyRef provider simplifies code by automating cleanup tasks before a scope is destroyed. This means you can create cleaner code without needing to use inheritance.
Additionally, the takeUntilDestroyed
operator can streamline your code even further.
Give it a try and see how much easier it is to work with Angular!
P.S. Feeling excited? Check out another cool new feature - Required Inputs!