When you want to display a list of data in Angular, you use *ngFor directive.


<ul>
	<li *ngFor= « let book of books »>{{ book.name }}</li>
</ul>


The *ngFor directive instantiates a template once by item from the collection.


When the collection changes (as for example when you get new data from the server), Angular needs to rebuild all items because it cannot keep track of them, and does not know which one have been removed or added.


This is because of Angular default behavior of using object identity to track insertions and deletions : even if the data has not changed, the second response from the server will produce new objects with different identities !


This produces big DOM manipulations, which can be very expensive.



We can help Angular to track items by providing a trackBy function. The trackBy function takes the index and the current item as arguments and needs to return the unique identifier for this item.


Here is the complete code with trackBy:

import { Component, OnInit } from "@angular/core";

@Component({
 selector: "app-root",
 styleUrls: ["./app.component.scss"],
 template: `
  
   <button (click)="getBooks()">Refresh list</button>
  
   <ul>
    <li *ngFor="let book of books; trackby: trackByFn">{{ book.name }}</li>
   </ul>
  
   `
  })
  export class AppComponent implements OnInit {
  
   public books = [];
  
   ngOnInit() {
    this.getBooks();
   }
  
   public getBooks() {
      this.books = this.books.length > 4 ? [
         { id: 0, name: 'Don Quixote - Miguel De Cervantes' },
         { id: 1, name: 'Robinson Crusoe - Daniel Defoe' },
         { id: 2, name: 'Frankenstein - Mary Shelley' },
         { id: 3, name: 'Anna Karenina - Leo Tolstoy' },
      ] : [
         { id: 0, name: 'Don Quixote - Miguel De Cervantes' },
         { id: 1, name: 'Robinson Crusoe - Daniel Defoe' },
         { id: 2, name: 'Frankenstein - Mary Shelley' },
         { id: 3, name: 'Anna Karenina - Leo Tolstoy' },
         { id: 4, name: 'The Trial - Franz Kafka' },
      ];
   }
  
   public trackByFn(index: number, item) {
      return index;
   }
}


Now, even when the collection changes, Angular can track which item has been inserted or deleted according to their unique identifier provided by the trackBy, and destroy only the items that changed.



Rendering is a sensitive subject, especially when you work with big lists of data, and the use of trackBy can improve performance a lot.