角度跟踪通过返回* ngFor vs项目ID中的索引 [英] Angular trackBy returning the index in *ngFor vs item id

查看:69
本文介绍了角度跟踪通过返回* ngFor vs项目ID中的索引的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个很大的ngFor,经常使用异步数据进行更改. TrackBy只允许刷新更改的部分,添加它时我真的感到与众不同. 例如,在我看来,使用trackBy返回唯一ID有什么好处. 但是我有时会看到样本返回当前索引.

I have a huge ngFor, changing frequently with asynchronous data. TrackBy allows to only refresh the changing part, and I really feel the difference when I add it. It seems clear to me what is the benefit to have a trackBy returning a unique ID, for example. But I sometime see samples returning the current index.

public trackByFn(index, item) { return index }

在我的表格中,如果我直接返回"index"或"item.id",则不会发现任何差异.两者似乎都优化了渲染效果(但是我可能没有发现一些错误的边框情况).

In my table, I don't notice any differences if I directly return 'index' or 'item.id'. Both seems optimize the render (but I maybe didn't catch some bugged border cases).

那么,有人可以解释一下我返回索引时到底发生了什么吗?

So, can someone explain me what exactly happen when I return the index?

推荐答案

根据您的评论和我自己的好奇心,我挖了棱角分明的

Based on your comment, and my own curiosity, I dug into the angular differ code. I can break it down for you what happens in the 3 different scenarios and I suppose it's a nice to have knowledge as well:

第一种情况:

未定义trackBy:<div *ngFor="let obj of arrayOfObj">{{obj.key}}</div>

如果未定义trackBy,则对数组进行有角度的迭代,创建DOM元素,并将数据绑定在[ngForOf]内的模板中. (以上代码可以写成):

If there is no trackBy defined, angular iterates over the array, creates the DOM elements and binds the data in the template within the [ngForOf]. (Above code can be written as):

<ng-template ngFor let-obj [ngForOf]="arrayOfObj">
  <div>{{obj.key}}</div>
</ng-template>

因此,基本上,它将创建所有这些div元素.最初,这对于所有3种可能性都是相同的.现在,来自API的新数据或多或少都是相同的数据,但是对数组对象的引用会更改,并且初始数组中对象的所有引用都是不同的.如果未定义trackBy函数,则按标识===进行角度比较.这与字符串,数字和其他原语(不是那么多)配合得很好.但是对于对象,这不会.因此,如果它开始检查是否有更改,现在会发生什么.它不再能找到原始对象,因此它删除了DOM元素(如果对象决定返回,则将其实际存储在以后使用),并从头开始构建所有模板.

So basically, it creates all those div elements. Initially this is the same for all 3 possibilities. Now new data arrives from the API, more or less the same data, but the reference to the array object changes, and all the references from the objects in the initial array are different. If you do not define a trackBy function, angular compares by identity ===. This will go well with strings, numbers and other primitives (not that many out there). But for objects, this will not. So what happens now if it starts checking if there are changes. It cannot find the original objects anymore so it removes the DOM elements (actually stores it somewhere for later use, if an object decides to come back), and build all the templates from scratch.

即使数据没有更改,第二个响应也会生成具有不同标识的对象,并且Angular必须拆除整个DOM并重建它(就像删除了所有旧元素并插入了所有新元素一样).

您可以想象这可能会导致CPU饥饿,以及内存不足.

You can imagine that this can be quite cpu hungry, and memory hungry.

第二种情况:

trackBy用对象键定义:

<div *ngFor="let obj of arrayOfObj;trackBy:trackByKey">{{obj.key}}</div>

trackByKey = (index: number, obj: object): string => {
  return object.key;
};

让我们先做一个.这是最快的.因此,我们正处于新数据进入的时刻,具有与以前不同身份的对象.在这一点上,角度迭代此trackBy函数上的所有新对象,并获取对象的标识.然后,它将交叉引用现有(如果没有找到,则将其删除)现有DOM元素.如果找到,它将仍然更新模板内进行的所有绑定.如果找不到,它将检查以前删除的对象,如果仍然找不到它,它将从模板创建一个新的DOM元素并更新绑定.所以,这很快.只是寻找已经创建的DOM元素,并更新绑定,而angular可以快速实现.

Let's do this one first. It's the quickest one. So we are at the point where new data comes in, with objects of different identities than before. At this point, angular iterates all new objects over this trackBy function and get the identity of the object. It will than cross reference it to existing (and previously deleted if not found) DOM elements. If found, it will still update any bindings made inside the template. If not found, it will check previously removed objects, and if it still cannot find it, it will create a new DOM element from the template and update the bindings. So, this is quick. Just looking for already created DOM elements, and update bindings, which angular can do quick quick quick.

第三种情况:

trackBy用数组索引定义

<div *ngFor="let obj of arrayOfObj;trackBy:trackByIndex">{{obj.key}}</div>

trackByIndex = (index: number): number => {
  return index;
};

这与trackBy对象键是相同的故事,但是差别很小,如果您去玩弄数组中的元素,那么模板中的绑定将不断更新.但这仍然是快速的,但很可能不是最快的方法:),尽管它比重新创建整个DOM快得多.

This is the same story as the trackBy object key, but with the small difference that if you go play juggle with the elements inside the array, the bindings within the templates keep getting updated. But this is still fast, but most likely not the fastest way :), although it's a lot faster than recreating the entire DOM.

希望您现在能有所作为.不过有些额外的东西.如果您有很多使用相同方式访问其标识的业务对象(例如属性.id.key),则可以扩展本机*ngFor并创建具有此trackBy的自己的结构化指令内置函数.不过未经测试的代码:

Hope you get the difference now. A little something extra though. If you have a lot of business objects which all have the same way to access their identity, like a property .id or .key, you can extend the native *ngFor and create your own structural directive which has this trackBy function built in. Untested code though:

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;
}

这篇关于角度跟踪通过返回* ngFor vs项目ID中的索引的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆