来自 API 的异步数据的 ngFor 和 trackBy 仍在重新渲染 DOM?
ngFor and trackBy with async data from API still re-rendering DOM?
我想将 ngFor
与 async
数据(从 API 加载)和 trackBy
一起使用,以提高性能并在没有 DOM 的情况下更新列表 flashing/flickering数据更新时。
如果数据是静态的 - 一切正常。但是当我尝试使用从 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>
发生这种情况是因为您正在为另一个可观察实例更改可观察对象。 ngFor 检测到 重新渲染 dom 时设置了新的可观察对象 。正确的工作方式是不设置新的 observable,只是 在 observable.
上推送新项目
这是一个应用此方法的 stackblitz 示例,您会看到 dom 未重新呈现:https://stackblitz.com/edit/angular-wslaz7
我不知道为什么带有静态数据的示例不重新呈现 dom,这可能是整个操作 'sync' 时的副作用,因为如果我添加of() 之后的 delay() 如:
this.episodes = of([
{id: 1, name: "name1"},
{id: 2, name: "name2"}
]).pipe(delay(100));
您会看到它会重新呈现项目。
我们可以问 angular 团队为什么在没有应用 delay() 时不重新渲染,我不知道。
希望对您有所帮助!
我想将 ngFor
与 async
数据(从 API 加载)和 trackBy
一起使用,以提高性能并在没有 DOM 的情况下更新列表 flashing/flickering数据更新时。
如果数据是静态的 - 一切正常。但是当我尝试使用从 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>
发生这种情况是因为您正在为另一个可观察实例更改可观察对象。 ngFor 检测到 重新渲染 dom 时设置了新的可观察对象 。正确的工作方式是不设置新的 observable,只是 在 observable.
上推送新项目这是一个应用此方法的 stackblitz 示例,您会看到 dom 未重新呈现:https://stackblitz.com/edit/angular-wslaz7
我不知道为什么带有静态数据的示例不重新呈现 dom,这可能是整个操作 'sync' 时的副作用,因为如果我添加of() 之后的 delay() 如:
this.episodes = of([
{id: 1, name: "name1"},
{id: 2, name: "name2"}
]).pipe(delay(100));
您会看到它会重新呈现项目。
我们可以问 angular 团队为什么在没有应用 delay() 时不重新渲染,我不知道。
希望对您有所帮助!