Hata Ansiklopedisi

İzleme ifadesi DOM yapısının yeniden oluşturulmasına neden oldu.

@for döngüsünde belirtilen kimlik izleme ifadesi, tüm öğelere karşılık gelen DOM'un yeniden oluşturulmasına neden oldu. Bu, değişmez (immutable) veri yapılarıyla çalışırken yaygın olarak meydana gelen çok pahalı bir işlemdir. Örneğin:

@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}));
  }
}

Sağlanan örnekte, öğelerin "done" durumu değiştirildiğinde tüm görünümlerle (DOM düğümleri, Angular direktifleri, bileşenler, sorgular vb.) birlikte listenin tamamı yeniden oluşturulur (!). Burada done özelliğine nispeten ucuz bir bağlama güncellemesi yeterli olurdu.

Yüksek performans cezasının yanı sıra, DOM ağacının yeniden oluşturulması DOM elementlerindeki durumun kaybına (örn.: odak, metin seçimi, iframe'de yüklenen siteler vb.) neden olur.

Hatayı düzeltme

İzleme ifadesini, nesne kimliğinden bağımsız olarak bir koleksiyondaki bir öğeyi benzersiz şekilde tanımlayacak şekilde değiştirin. Tartışılan örnekte, doğru izleme ifadesi benzersiz id özelliğini (item.id) kullanır:

@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}));
  }
}