Improve *ngFor performance with trackBy
Angular uses reference comparison for objects in the list by default. This might not be the optimal approach, especially when you update your list's data from the server. Instead, you could be using some unique and stable identifier that your objects have. Thanks to comparing by the id, Angular won't need to rerender all elements every time you fetch an updated list from an API (object references will be changed but ids won't change).
Fewer computations -> performance gain! 🥳
As we all know, in terms of performance, DOM manipulations are rather expensive than regular JavaScript code.
Angular’s ngFor
Directive is highly optimized in a way that reduces DOM manipulation to a bare minimum.
So, if an element is added or removed from an array, the whole list isn’t getting re-rendered. Whereas it’d use all the existing DOM elements and the only new element gets created or removed.\
Similarly, when the element changes its position in the array, only that change in position of DOM element get noticed.
Angular determines all the DOM manipulation and does all optimisation since it conducts identification of each object in the array. It uses the* reference of the object** for that.*
Why & when to use trackBy then?
Unfortunately, Angular's default method of identifying objects by its reference is quite constrained especially in circumstances where a reference shift can’t be prevented.
If we are working with REST API or any type of immutable data structure, the reference of each object will be kept on changing. This forces Angular to give up its default optimisations and forces it to re-render the whole data set. This is because every reference is modified and therefore every object seems new to Angular.
As you can probably tell this heavily impact the performance. Especially if your collection is huge.
To avoid this, we can help Angular to identify each object in the collection by having a trackBy
attribute.
A trackBy attribute allows us to define a function that returns a unique identifier for each iterable element.
This helps bypass unnecessary and expensive change detection when the data set changes, say for example on receiving new data from an API call.
How to use trackBy
?
We need to create a function within our component that matches TrackByFunction interface. The trackby function takes the index and the current element as arguments and it returns the unique identifier for this element.
1interface TrackByFunction<T> { 2 (index: number, item: T): any; 3} 4 5// component level function should look something like this 6function trackByTransaction(index: number, item: Transaction): string { 7 return item.id; 8}
And use it in the template like this:
1<div *ngFor="let item of txnList; trackBy: trackByData"> 2 <!-- do stuff --> 3</div>