エラー百科辞典

Tracking expression caused re-creation of the DOM structure.

@for ループで指定されたアイデンティティトラック式が、_すべての_アイテムに対応するDOMの再作成を引き起こしました。これは、イミュータブルなデータ構造を扱う際に発生する一般的な操作で、非常に高価です。例:

@Component({
  template: `
    <button (click)="toggleAllDone()">All done!</button>
    <ul>
      @for (todo of todos; track todo) {
        <li>{{ todo.task }}</li>
      }
    </ul>
  `,
})
export class App {
  todos = [
    {id: 0, task: 'understand trackBy', done: false},
    {id: 1, task: 'use proper tracking expression', done: false},
  ];

  toggleAllDone() {
    this.todos = this.todos.map((todo) => ({...todo, done: true}));
  }
}

この例では、アイテムの "done" ステータスを切り替えた後、すべてのビュー(DOMノード、Angularディレクティブ、コンポーネント、クエリなど)を含むリスト全体が再作成されます(!)。ここでは、done プロパティへの比較的安価なバインディング更新で十分です。

DOMツリーを再作成すると、高いパフォーマンスペナルティに加えて、DOM要素のステート(例:フォーカス、テキストの選択、iframeでロードされたサイトなど)が失われます。

エラーの修正

アイテムのオブジェクトアイデンティティに関係なく、コレクション内のアイテムをユニークに識別するようにトラック式を変更します。説明した例では、正しいトラック式はユニークな id プロパティ(item.id)を使用します。

@Component({
  template: `
    <button (click)="toggleAllDone()">All done!</button>
    <ul>
      @for (todo of todos; track todo.id) {
        <li>{{ todo.task }}</li>
      }
    </ul>
  `,
})
export class App {
  todos = [
    {id: 0, task: 'understand trackBy', done: false},
    {id: 1, task: 'use proper tracking expression', done: false},
  ];

  toggleAllDone() {
    this.todos = this.todos.map((todo) => ({...todo, done: true}));
  }
}