ngFor和trackBy是否使用来自API的异步数据仍在重新渲染DOM?

时间:2019-10-28 11:01:23

标签: javascript angular rxjs ngfor

我想将ngForasync数据(从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 :(得分:0)

之所以发生这种情况,是因为您正在更改另一个可观察实例的可观察对象。 ngFor检测到设置新的可观察对象时重新渲染dom 。正确的工作方式是不设置新的可观察对象,而只是在可观察对象上推送新项目

这是一个采用这种方法的堆叠闪电示例,您将看到dom没有重新渲染:https://stackblitz.com/edit/angular-wslaz7

我不知道为什么带有静态数据的示例不重新渲染dom,这可能是整个操作“同步”时的副作用,因为如果我在of()之后添加了delay() ),例如:

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

您会看到它将重新渲染项目。

我们可以问角度小组,当不应用delay()时,为什么不重新渲染,我不知道。

希望这会有所帮助!