简体   繁体   中英

How to combine get .pipe takeUntil and subscribe into one function in Angular with RxJX?

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 component to unsubscribe when component 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;
   }
)

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.com/@adrianbrand/angular-state-management-with-rxcache-468a865fc3fb

Generally your services don't have to be destroyed/disabled after some component 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 completed immediately after some action, you will have memory leaks (Angular can create/initialize each component multiple times). Speaking of Angular 's http , all of get , post , put and delete calls are completed 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 become long-lasting and each component that is subscribed to this messaged should unsubscribe during onDestroy cycle. If you don't do this, Angular can initialize your component 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 common 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 component is destroyed.

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 components 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM