ngFor и trackBy с асинхронными данными из API все еще перерисовывают DOM? - PullRequest
0 голосов
/ 28 октября 2019

Я хочу использовать ngFor с async данными (загруженными из API) и trackBy для повышения производительности и обновления списка без мигания / мерцания DOM при обновлении данных.

Если данные статические- все работает отлично. Но когда я пытаюсь использовать данные, загруженные из API - trackBy не работает.

LIVE

из API: https://stackblitz.com/edit/angular-hx4p39
статические данные: https://stackblitz.com/edit/angular-myb6vj

Компонент

export class AppComponent {

  constructor(private http: HttpClient){}

  comments$: Observable<Comment[]> = this.http.get<Comment[]>(`https://jsonplaceholder.typicode.com/comments?_start=0&_limit=5`);

  add() {
    this.comments$ = this.http.get<Comment[]>(`https://jsonplaceholder.typicode.com/comments?_start=0&_limit=6`);
  }

  edit() {
    this.comments$ = this.comments$.pipe(
      map(comments => {
        comments.map( comment => {
          if(comment.id === 5){ comment.name = 'edit'; }
          return comment;
        });
        return comments;
      })
    );
  }

  itemTrackBy(index: number, item: Comment) {
    return item.id;
  }
}

interface Comment {
  postId;
  id;
  email;
  name;
  body;
}

Шаблон

<button (click)="add()">Make 6</button>
OR
<button (click)="edit()">edit 5-th element</button>

<ul>
  <li *ngFor="let comment of (comments$ | async); trackBy: itemTrackBy">
    {{comment.id}} - {{comment.name}}
  </li>
</ul>

1 Ответ

0 голосов
/ 28 октября 2019

Это происходит потому, что вы меняете наблюдаемое на другой наблюдаемый экземпляр. ngFor обнаруживает, что повторно отображает dom, когда установлена ​​новая наблюдаемая . Правильный способ работы состоит в том, чтобы не устанавливать новую наблюдаемую вещь, это просто помещать новые элементы в наблюдаемую .

Вот пример стекаблика, который применяет этот подход, вы увидите, чтоdom не перерисовывается: https://stackblitz.com/edit/angular-wslaz7

Я не знаю, почему пример со статическими данными не перерисовывает dom, может быть, это побочный эффект, когда вся операция 'sync', поскольку, если я добавлю delay () после of (), например:

this.episodes =  of([
      {id: 1, name: "name1"},
      {id: 2, name: "name2"}
    ]).pipe(delay(100));

, вы увидите, что он будет перерисовывать элементы.

Мы могли бы спросить команду angular, почемуне рендерится, когда не применяется delay (), я понятия не имею.

Надеюсь, это поможет!

...