In Angular every time a endpoint needs to be queried, this code needs to be called:
this.service.getSomeData()
.pipe(takeUntil(this.onDestroy$))
.subscribe((message: any) => {
some code here;
}
takeUntil is a function in a ponent to unsubscribe when ponent is destroyed.
How to refactor the code above so it wont be needed to type all of this every time a resource is used? So it looks like this at the end (more or less?):
this.service.getSomeData(
(message: any) => {
some code here;
}
)
In Angular every time a endpoint needs to be queried, this code needs to be called:
this.service.getSomeData()
.pipe(takeUntil(this.onDestroy$))
.subscribe((message: any) => {
some code here;
}
takeUntil is a function in a ponent to unsubscribe when ponent is destroyed.
How to refactor the code above so it wont be needed to type all of this every time a resource is used? So it looks like this at the end (more or less?):
this.service.getSomeData(
(message: any) => {
some code here;
}
)
Share
Improve this question
asked Oct 8, 2019 at 9:16
Tom SmykowskiTom Smykowski
26.2k57 gold badges165 silver badges247 bronze badges
3 Answers
Reset to default 5Generally your services don't have to be destroyed/disabled after some ponent is unmounted from view/dom. Treat them like a layer of code to perform some data transformation or fetching.
Q: Why does everyone use takeUntil(this.destroyed$)
or this.subscription.unsubscribe()
?
A: The Observable
lives as long as there is at least one subscriber for it. So if you have some long-living observables that are not pleted immediately after some action, you will have memory leaks (Angular can create/initialize each ponent multiple times). Speaking of Angular
's http
, all of get
, post
, put
and delete
calls are pleted after the backend call is done. This means that you don't have to add unsubscribe
in onDestroy
hook or use takeUntil
.
If you have established a Websocket
connection and are listening to some messages, your stream bee long-lasting and each ponent that is subscribed to this messaged should unsubscribe during onDestroy
cycle. If you don't do this, Angular can initialize your ponent multiple times (this usually happens with *ngIf=""
statements) and multiple subscriptions are created but never destroyed. This leads to memory leaks.
Unfortunately this is a mon problem for most of the Angular projects that can be solved by either manual unsubscribe
/takeUntil
or by using the async
pipe that automatically performs unsubscribe
after the ponent is destroyed.
One option is to use the async pipe in your template to manage the subscriptions
data$ = this.service.getSomeData();
and in your template
<ng-container *ngIf="data$ | async as data">
{{ data | json }}
You can use the template variable data here that magically updates every time data$
emits and no need to unsubscribe as the async pipe manages the subscription for you
</ng-container>
If the observable emits data that is not in the shape you need for your template then use a map function
data$ = this.service.getSomeData().pipe(map(data => functionThatTransformsData(data)));
You can have a read of the pattern I use with my state management library here https://medium./@adrianbrand/angular-state-management-with-rxcache-468a865fc3fb
I am glad you asked that, I came across this Angular AutoUnsubscribe (I am referencing this because I found that the logic to implement this is really beautiful.)
Its relatively easy to use, and workes across all declarables(pipes, directives, and ponents obviously.)
Now to omit both the subscribing and unsubscribing part (that I won't suggest), it pretty simple, and straight forward.
Earlier you had something like
getSomeData(): Observable<any> {
// for eg
return this.http.get();
}
You have to Change it to :
getSomeData(callback, onDestroy$): Observable<any> {
this.http.get(...).pipe(takeUntil(onDestroy$)).subscribe(val => callback(val));
}
Then we'll be able to have what we finally wanted. Cheers.