DEV Community

Cover image for The Ultimate Answer To The Very Common Angular Question: subscribe() vs | async Pipe
Tomas Trajan πŸ‡¨πŸ‡­
Tomas Trajan πŸ‡¨πŸ‡­

Posted on • Originally published at Medium

The Ultimate Answer To The Very Common Angular Question: subscribe() vs | async Pipe

Most of the popular Angular state management libraries like NgRx expose application state in a form of a stream of state objects. This is usually implemented with the help of RxJS Observables.

The state updates get pushed to the components which react by re-rendering their templates to display the most recent version of the application state.

There are multiple ways in which it is possible to consume this observable stream of state updates by the components, the two most popular being:

  • Using the subscribe() method and storing the state on the component instance, todos$.subscribe(todos => this.todos = todos)...

  • The | async pipe unwraps the state object directly in the component’s template, <li *ngFor=”let todo of todos$ | async”></li>...

I have been thinking about this question and related trade-offs for quite some time now. I was mostly in favor of using subscribe() but couldn’t really point out exact reasons why.

Read more...

Top comments (8)

Collapse
 
chiangs profile image
Stephen Chiang

I was thinking...if I wanted to do some operation in a component based on a boolean stream, I am forced to subscribe so that I can call the the operation when the right boolean value is received right?

I would have to go from:

this.foo$ = this.store.pipe(select(foo));

to:

this.foo$ = this.store.select(state => {
      this.foo = state.store.foo;
      if (this.foo) {
        this.operationOnFoo();
      }
    });

Is this a correct assumption?

Collapse
 
tomastrajan profile image
Tomas Trajan πŸ‡¨πŸ‡­

You can also do this.fooExists$ = this.store.pipe(select(foo), filter(foo => !!foo)); then you can also this.fooExists$.subscribe(operation). But why do you have to call something for every foo? Can't it be implemented using ngrx @Effect() ?

Collapse
 
chiangs profile image
Stephen Chiang

I only need it to happen once and only one component is listening for it... Sort of like this component telling a sibling component that it is ready to do something... So I thought an effect would be Overkill, plus I'm not calling a new Action, the operation happens internally to the listening component.

Collapse
 
chiangs profile image
Stephen Chiang

Would i need to manually unsubscribe in OnDestroy if I did it this way (not @Effect) as you have described?

Thread Thread
 
tomastrajan profile image
Tomas Trajan πŸ‡¨πŸ‡­

Yes, whenever you do explicit .subscribe() call, you are automatically responsible to call .unsubscribe(). Even better would be to use .pipe(takeUntil(onDestroy$)) which is declarative ;)

Thread Thread
 
chiangs profile image
Stephen Chiang • Edited

awesome, thanks!

so then I would also need to do this, right?

ngOnDestroy() {
    this.onDestroy$.next(true);
    this.onDestroy$.unsubscribe();
  }
Thread Thread
 
tomastrajan profile image
Tomas Trajan πŸ‡¨πŸ‡­ • Edited
ngOnInit() {
   this.source$.pipe(takeUntil(onDestroy$)).subscribe()
}

ngOnDestroy() {
    this.onDestroy$.next(true);
    this.onDestroy$.complete()
}

CHeers!

Collapse
 
chiangs profile image
Stephen Chiang • Edited

I have been using subscribe in ngOnInit and creating a subscription manager to unsub in OnDestroy which was ok because of couldn't definitely find out which way was better, but then just before this article came out I learned that using the async pipe handled the unsub for me, and now one learned it's also more performant so now I'm trying to use that as much as possible these days. Thanks for this article! I'm excited about the growing presence of angular articles here on Dev.