概要
Angular の ngForにはtrackBy
という設定項目があります。
ngForはtrackBy
を使用しない場合、コレクションに変更があったら全てのDOMを再生成します。
trackBy
を使用することで変更箇所のDOMのみ再生成するように設定できます。
再描画が多いngForを使用している箇所ではパフォーマンスチューニングの一環としてtrackBy
の使用をおすすめします。
実行環境
- Node.js 10.9.x
使用ライブラリ
- Angular 7.1.x
実装時の注意点
trackBy
の戻り値は一意な値を戻してください。
サンプルソース
list.component.ts
import { Component, Input, OnInit, OnDestroy } from '@angular/core'; @Component({ selector: 'custom-list', template: `<li>{{num}}</li>` }) export class ListComponent implements OnInit, OnDestroy { @Input() num = 0; @Input() title = 'list'; ngOnInit(): void { console.log(`${this.title}: init - ${this.num}`); } ngOnDestroy(): void { console.log(`${this.title}: destroy - ${this.num}`); } }
app.component.html
<div style="margin-top: 10px;"> <div> <h4> Non trackBy </h4> <div> <button (click)="setItem1()">Apply</button> </div> <div> <ul> <ng-container *ngFor="let item of item1"> <custom-list [num]="item.id" title="non-trackBy"></custom-list> </ng-container> </ul> </div> </div> <div style="margin-top: 10px;"> <h4> trackBy </h4> <div> <button (click)="setItem2()">Apply</button> </div> <div> <ul> <ng-container *ngFor="let item of item2; trackBy: trackByItem"> <custom-list [num]="item.id" title="trackBy"></custom-list> </ng-container> </ul> </div> </div> </div>
app.component.ts
import { Component } from "@angular/core"; interface ListData { id: number; } @Component({ selector: 'app-root', templateUrl: './app.component.html' }) export class AppComponent { item1: ListData[] = []; item2: ListData[] = []; setItem1(): void { this.item1 = this.createList(); } setItem2(): void { this.item2 = this.createList(); } /** * ngFor trackBy setting. * @param index * @param value */ trackByItem(index: number, value: ListData): number { return value ? value.id : null; } private createList(): ListData[] { const items = new Array<ListData>(); const length = Math.floor(Math.random() * 7) + 3; for (let i = 0; i < length; i++) { while (true) { const value = Math.floor(Math.random() * 10) + 1; if (items.findIndex(item => item.id === value) < 0) { items.push({ id: value }); break; } } } return items; } }
実行結果
trackBy未使用
- ngForの対象の全てのDOMの生成・破棄が行われているのが分かります。
trackBy使用
- 差分箇所のみDOMの生成・破棄が行われているのが分かります。