- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我有一个巨大的 ngFor,经常随着异步数据变化。 TrackBy允许只刷新变化的部分,加进去的时候才真正感受到区别。例如,让 trackBy 返回唯一 ID 对我来说似乎很清楚有什么好处。但我有时会看到样本返回当前索引。
public trackByFn(index, item) { return index }
在我的表中,如果我直接返回 'index' 或 'item.id',我没有注意到任何差异。两者似乎都优化了渲染(但我可能没有发现一些错误的边界情况)。
那么,有人能解释一下当我返回索引时到底发生了什么吗?
最佳答案
根据您的评论和我自己的好奇心,我深入研究了 Angular differ code .我可以为您分解在 3 种不同情况下发生的情况,我想拥有知识也是一件好事:
第一种情况:
No
trackBy
defined:<div *ngFor="let obj of arrayOfObj">{{obj.key}}</div>
如果没有trackBy
已定义, Angular 遍历数组,创建 DOM 元素并在 [ngForOf]
中绑定(bind)模板中的数据. (以上代码可以写成):
<ng-template ngFor let-obj [ngForOf]="arrayOfObj">
<div>{{obj.key}}</div>
</ng-template>
所以基本上,它会创建所有这些 div 元素。最初这对于所有 3 种可能性都是相同的。现在新数据从 API 到达,或多或少是相同的数据,但对数组对象的引用发生了变化,并且来自初始数组中对象的所有引用都不同。如果你没有定义 trackBy 函数,angular 会按身份进行比较 ===
.这适用于字符串、数字和其他原语(不是那么多)。但是对于对象,这不会。那么如果它开始检查是否有变化,现在会发生什么。它无法再找到原始对象,因此它会删除 DOM 元素(实际上将其存储在某处以供以后使用,如果对象决定返回),并从头开始构建所有模板。
Even if the data hasn't changed, the second response produces objects with different identities, and Angular must tear down the entire DOM and rebuild it (as if all old elements were deleted and all new elements inserted).
您可以想象这会非常耗费 CPU 和内存。
第二种情况:
trackBy
defined with object key:
<div *ngFor="let obj of arrayOfObj;trackBy:trackByKey">{{obj.key}}</div>
trackByKey = (index: number, obj: object): string => {
return object.key;
};
让我们先做这个。这是最快的。所以我们正处于新数据进来的时刻,具有与以前不同身份的对象。此时,angular 在这个 trackBy 函数上迭代所有新对象并获得对象的标识。它会将它交叉引用到现有的(如果没有找到则之前删除的)DOM 元素。如果找到,它仍将更新在模板内进行的任何绑定(bind)。如果没有找到,它将检查之前删除的对象,如果仍然找不到,它将从模板创建一个新的 DOM 元素并更新绑定(bind)。所以,这很快。只是寻找已经创建的 DOM 元素,并更新绑定(bind),angular 可以快速快速地完成。
第三种情况:
trackBy
defined with array index
<div *ngFor="let obj of arrayOfObj;trackBy:trackByIndex">{{obj.key}}</div>
trackByIndex = (index: number): number => {
return index;
};
这与 trackBy 对象键的故事相同,但有一点不同,即如果你去玩弄数组中的元素,模板中的绑定(bind)会不断更新。但这仍然很快,但很可能不是最快的方法 :),尽管它比重新创建整个 DOM 快得多。
希望您现在有所不同。不过还有一些额外的东西。如果你有很多业务对象,它们都有相同的方式来访问它们的身份,比如属性 .id
或 .key
,您可以扩展 native *ngFor
并创建你自己的结构指令,它有这个 trackBy
内置函数。虽然未经测试的代码:
export interface BaseBo {
key: string;
}
@Directive({selector: '[boFor][boForOf]'})
export class ForOfDirective<T extends BaseBo> extends NgForOf<T> {
@Input()
set boForOf(boForOf: T[]) {
this.ngForOf = boForOf;
}
ngForTrackBy = (index: number, obj: T) => obj.key;
}
关于Angular trackBy 返回 *ngFor 中的索引 vs item id,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54478273/
这里我试图在 FlatList 中显示一个名为“posts”的数组。 render() { console.log(this.props.posts); return (
这是我的代码: {{day(list)}} {{list.weather[0].description}}
我是 Mahout 的新手,并且仍在使用它。 我的问题是,将 Item-Item 和 User-Item 结合起来是否合适? 我的用例是,一个社交网络应用会尝试根据用户历史数据(优先级较高)为当前用户
下午好, 我按数据库搜索以测试特定类测试,当我放置一个新项目时,如果列表包含该项目。 @Test public void insertAndDeleteTask() throws Interrupte
我有一个关于 ionic 框架的问题,我希望有人能帮助我...我有一个带有“ion-item-right”的 ionic 列表。这一切都可以,按钮在右边。现在我需要其他三个居中的图标,这样我就有了:文
我经常遇到类似下面的代码: if ( items != null) { foreach(T item in items) { //... } } 基本上,if 条件确
我最近问了a question about LocalStorage .使用 JSON.parse(localStorage.item) 和 JSON.parse(localStorage['item
我最近问了a question about LocalStorage .使用 JSON.parse(localStorage.item) 和 JSON.parse(localStorage['item
这个问题已经有答案了: Type mismatch: cannot convert from Item to Item (1 个回答) 已关闭 7 年前。 我很困惑。我无法将外部类的实例变量 Node
我目前正在使用 MUI Grid(但我对替代解决方案持开放态度)并且我想要并排放置两个组件:最右边的组件占 400px宽度和左侧组件占据其余部分。 || || || 当页面宽度缩小时: | | ||
我最近问过a question about LocalStorage 。使用 JSON.parse(localStorage.item) 和 JSON.parse(localStorage['item
public class Document extends Model { ... @ManyToMany public Set accessors; ... } 我想选择访问者包含某个用户的所有文档
我正在使用 selenium webdriver 为单页 Web 应用程序开发一个 Java 框架,使用以下模式:PageObject、SlowLoadableComponent(责任链)、PageF
最近在学习C,在网上发现了一个问题。问题是: What is the problem with this function in terms of memory allocation? What is
我有这个代码 ( -1 ? true : false} /> {genre.item.name}
在ASP.Net中使用DataGrid时真的没有快捷方法吗 (e.Item.ItemType==ListItemType.Item || e.Item.ItemType==ListItemType.A
我正在使用工作流程根据数据和一组要求将大量 pdf 从一个位置复制到其他大坝位置。我正在使用以下代码 Assets damAsset = manager.createAsset(path, is, m
我是 PowerShell 的新手。 我正在尝试自动将 dll 组件从源服务器上的文件夹部署到目标服务器上的多个文件夹。这看起来应该很简单:将组件从源服务器上的源(部署)文件夹复制到目标服务器上的文件
我的代码: for column_name, column_data in summary_words.iteritems(): if column_name != "summary" and
我的代码: for column_name, column_data in summary_words.iteritems(): if column_name != "summary" and
我是一名优秀的程序员,十分优秀!