DEV Community

Tomas
Tomas

Posted on

Performance tip for rendering large collections in Angular

Problem:
To render collection in Angular we use the built in directive *ngFor which works fine as long as we are just displaying or mutating the collection. A potential problem arise when we re-assign the variable holding the collection. Angular must then destroy all the old DOM-nodes and recreate them, even if only a few elements have changed, for a large collection this can create performance issues.

Solution:
Create a function that returns a unique id for each element in the collection, the function is then passed to the directive TrackedBy which we use together with *ngFor.

Before / Untutored:

Component

items = [
  {title: 'Cinnamon buns'},
  {title: 'Cup cakes'},
  {title: 'Croissants'}
];

update() {
  this.items = [
    {title: 'Cinnamon buns'},
    {title: 'Cup cakes'},
    {title: 'Croissants'},
    {title: 'Macarons'}
  ];
}

Template

<div *ngFor="let item of items">
  <app-item [text]="item.title"></app-item>
</div>

Log

naive - Cinnamon buns initialized
naive - Cup cakes initialized
naive - Croissants initialized
Updated data
naive - Cinnamon buns initialized
naive - Cup cakes initialized
naive - Croissants initialized
naive - Macarons initialized

After:

Component

items = [
  {title: 'Cinnamon buns'},
  {title: 'Cup cakes'},
  {title: 'Croissants'}
];

update() {
  this.items = [
    {title: 'Cinnamon buns'},
    {title: 'Cup cakes'},
    {title: 'Croissants'},
    {title: 'Macarons'}
  ];
}

itemsTrackedBy(index, item) {
  return item.text;
}

Template

<div *ngFor="let item of items; trackBy: itemsTrackedBy">
    <app-item [text]="item.title"></app-item>
</div>

Log

trackedBy - Cinnamon buns initialized
trackedBy - Cup cakes initialized
trackedBy - Croissants initialized
Updated data
trackedBy - Macarons initialized

Try it yourself:
https://stackblitz.com/edit/thllbrg-angular-fika-2

Official docs:
https://angular.io/guide/template-syntax#ngfor-with-trackby

Top comments (0)