使用未定义副作用的角跟踪功能

问题描述 投票:0回答:1

我在组件之一中频繁运行更改检测时遇到问题,因此我尝试对trackBy指令使用ngFor选项。

通过阅读,我了解到Angular将使用从您的trackyBy函数返回的值,因为它在下次运行更改检测时与diff相同。为了查看它是否满足我的需求,并尝试更好地理解它,我建立了一个游乐场。使用它时,我设置了用于返回未定义的trackyBy函数的返回值,但仍然得到了想要的结果。

TS:

import { Component } from '@angular/core';

@Component({
  selector: 'my-app',
  styleUrls: ['./app.component.scss'],
  templateUrl: './app.component.html',
})
export class AppComponent {
collection;
  constructor() {
    this.collection = [{id: 1, value: 0}, {id: 2, value: 0}, {id: 3, value: 0}];
  }

  getItems() {
    this.collection = this.getItemsFromServer();
  }

  getItemsFromServer() {
    return [{id: 5, value: 0}, {id: 2, value: 0}, {id: 3, value: 3}, {id: 4, value: 4}];
  }

  trackByFn(index, item) {
    return undefined;
  }
}

HTML:

    <ul>
      <li *ngFor="let item of collection;trackBy: trackByFn">{{ item.id }}hello {{item.value}}</li>
    </ul>
    <button (click)="getItems()">Refresh items</button>

第一次单击的结果是,所有项目均以其新值或ID重新呈现,但数组的索引1除外。第二次单击时,没有任何项目重新渲染,因为对象内没有任何变化。

所以我的问题是,为什么一个人总是对trackBy函数的返回值使用唯一的ID?我必须缺少某些东西,并且我不希望它以我尚未看到的方式影响我的应用程序。

angular typescript ngfor
1个回答
0
投票

官方的答案是,您使用trackBy避免为具有相同标识符的对象的新实例重新创建DOM中的元素。

[表面上,您的设置并不能证明ngFor不仅会忽略您在undefined中返回的trackByFn值,而且无论何时在模型中出现新实例都将重新创建DOM元素。] >

具有与现有对象相同ID的新项目可能已经更改了其他属性,因此无论您是否使用(或误用)trackBy,您都希望HTML正确无误。

设置

我使用您的代码创建了一个测试环境,除了我为*ngFor的源代码进行了分叉,以便可以添加自己的日志记录以跟踪*ngFor内部发生的情况。

我测试了三种情况:

A)trackByFn返回唯一ID

B)trackByFn返回undefined

C)不使用trackBy

我跟踪了以下每种情况下发生的情况

  1. 创建列表
  2. 部分替换一些列表数据
  3. 排序列表
  4. 重置列表数据
  5. 我在每个步骤中为“纯”测试分配了新的对象实例。

结果

1。创建列表

对于所有3种情况都是相同的-为列表中的每个项目创建一个DOM元素。

2。部分替换一些列表数据

A)删除已删除项目的DOM元素,并为新项目创建新的DOM元素。所有元素均已更新。

B)为索引超出原始数组范围的项目创建新的DOM元素。所有元素均已更新。

C)重新创建所有DOM元素。

3。排序列表

A)移动已移动位置的DOM元素

B)更新已移动位置的DOM元素

C)重新创建所有DOM元素

4。重置列表数据

A)删除已删除项目的DOM元素,并为新项目创建新的DOM元素。所有元素都已更新(与方案2相同)。

B)删除已删除项目的DOM元素。所有元素均已更新。

C)重新创建所有DOM元素。

结论

值得注意的是,这些测试是使用对象的新实例完成的。如果要重用对象引用,则*ngFor效率更高。

如果列表非常易变,则在DOM操作方面使用trackBy更有效。

令人惊讶的结果

[从我的测试看来,与从trackByFn返回唯一标识符时相比,您的示例执行的DOM操作更少。如果将3个项目替换为3个新项目,则您的方法将不会执行任何DOM操作,并且仍将以“正确”方式运行相同的更新方法。 “ proper”方法将删除原始的3个DOM元素,并添加3个新的DOM元素。

这表明我们可以只提供返回恒定值的trackByFn,而不会产生任何意外结果。通过查看源代码并对其进行处理,我看不到这是一个问题(除了使其他查看您代码的人感到困惑之外)。

这的确使我想知道,当重用旧的DOM元素似乎可以正常工作时,为什么默认实现必须重新创建所有DOM元素。我敢肯定有些情况我还没有考虑过,我很想听听他们的意见。

DEMO:https://stackblitz.com/edit/angular-anejhw

这变成了一些“有趣”的研究任务,而不是确定的答案,但希望它被证明是有用的。即使我已经证明从trackByFn返回恒定值似乎是性能最高的选项,但我仍然对在生产代码中使用这种方法犹豫不决。即使现在它适用于所有情况,如果将其作为漏洞“修复”,我也不会感到惊讶。

[ngForOf源代码:https://github.com/angular/angular/blob/master/packages/common/src/directives/ng_for_of.ts

© www.soinside.com 2019 - 2024. All rights reserved.