我想将ngFor
与async
数据(从API加载)和trackBy
一起使用,以提高性能并更新列表,而数据更新时DOM不会闪烁。
如果数据是静态的-一切正常。但是,当我尝试使用从API加载的数据时,trackBy
不起作用。
来自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>
答案 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()时,为什么不重新渲染,我不知道。
希望这会有所帮助!