Picci
Picci

Reputation: 17762

NgrxStore and Angular - Use the async pipe massively or subscribe just once in the constructor

I am starting to look at ngrx Store and I see the convenience to use the Angular async pipe. At the same time I am not sure whether using the Angular async pipe massively is a good choice.

I make a simple example. Let's assume that in the same template I need to show different attributes of an object (e.g. a Person) which is retrieved from the Store.

A piece of template code could be

<div>{{(person$ | async).name}}</div>
<div>{{(person$ | async).address}}</div>
<div>{{(person$ | async).age}}</div>

while the component class constructor would have

export class MyComponent {
  person$: Observable<Person>;

  constructor(
    private store: Store<ApplicationState>
  ) {
      this.person$ = this.store.select(stateToCurrentPersonSelector);
  }
.....
.....
}

As far as I understand this code implies 3 subscriptions (made in the template via the async pipe) to the same Observable (person$).

An alternative would be to define 1 property (person) in MyComponent and to have only 1 subscription (in the constructor) that fills the property, such as

export class MyComponent {
  person: Person;

  constructor(
    private store: Store<ApplicationState>
  ) {
      this.store.select(stateToCurrentPersonSelector)
                .subscribe(person => this.person = person);
  }
.....
.....
}

while the template uses standard property binding (i.e. without the async pipe), such as

<div>{{person.name}}</div>
<div>{{person.address}}</div>
<div>{{person.age}}</div>

Now the question

Is there any difference in terms of performance between the 2 approaches? Is the massive use of async pipe (i.e. a massive use of subscriptions) going to affect the efficiency of the code?

Upvotes: 53

Views: 16146

Answers (3)

Victor Godoy
Victor Godoy

Reputation: 1692

Neither, you should compose your application as smart and presentation components.

Advantages:

  • All buissness logic on the smart controller.
  • Just one subscribe
  • Reusability
  • The presentation controller has only one responsibility, only to present data and does not know from where the data come from. (loosely coupled)

Answering the last question:

The massive use of async pipe will affect the efficiency, because it will subscribe to every async pipe. You can notice this more if you are calling a http service, because it will call the http request for each async pipe.

Smart Component

@Component({
  selector: 'app-my',
  template: `
      <app-person [person]="person$ | async"></app-person>
`,
  styleUrls: ['./my.component.css']
})
export class MyComponent implements OnInit {

    person$: Observable<Person>;

    constructor(private store: Store<ApplicationState>) {}

    ngOnInit() {
        this.person$ = this.store.select(stateToCurrentPersonSelector);
    }

}

Presentation Component

@Component({
  selector: 'app-person',
  template: `
    <div>{{person.name}}</div>
    <div>{{person.address}}</div>
    <div>{{person.age}}</div>
`,
  styleUrls: ['./my.component.css']
})
export class PersonComponent implements OnInit {

    @Input() person: Person;

    constructor() {}

    ngOnInit() {
    }

}

For more info check:

Upvotes: 47

marxin
marxin

Reputation: 3922

Another possibility is to use construction like this:

<div *ngIf="person$ | async as per">
    <div>{{ per.name }}</div>
    <div>{{ per.address }}</div>
    <div>{{ per.age }}</div>
<div>

Although for reusable bits of code its possibily better to use presentation component method.

Please note this works in angular 5, not sure about other versions.

Upvotes: 22

John Hamm
John Hamm

Reputation: 504

You can add ".share()" to the end of any observable declarations. All of your async pipes on an observable will then share the same subscription:

this.name$ = Observable.create(observer => {
  console.log("Subscriber!", observer);
  return observer.next("john")
}).delay(2000).share();

this.httpget$ = http.get("https://api.github.com/").share();

Plunkr demonstrating: https://embed.plnkr.co/HNuq1jUh3vyfR2IuIe4X/

Upvotes: 14

Related Questions