Angular 防止重新创建元素

Angular prevent recreation of elements

所以我有一个组件可以加载 divs 动画。 div 是基于数据源显示的。

*注意:例子中我用了很多<any>,那是因为我还没有决定模型

apiService.ts

dataArray: Observable<Array<any>>;

constructor(){
   this.getUpdateData();
   setInterval(()=> this.getUpdateData(), 1000);
}

getUpdateData(){
    this.httpClientCall()
    .subscribe((response: any) => {
      this.dataArray = response;
    });
  }

component.html

<div class="panels" *ngFor="let data of apiService.dataArray">
    <div class="panel-that-has-animation">
        {{ data.some_value_that_can_be_updated }}
    </div>
</div>

简单分解:我每分钟从远程拉取数据,并让响应为dataArray内的新数据。

我遇到的问题是每次更新时,整个 panels div 的内容都会被替换。 我只想更新值而不是重新渲染整个 div。

数组本身由对象组成,我真正喜欢做的是更新数组中的对象 属性,而不是替换整个对象数组。更确切;比较 2 个数组并检查对象的属性是否存在差异。

示例:

[ 
 0: {id: 1, name: a, group: 'a'},
 1: {id: 2, name: b, group: 'b'},
 2: {id: 3, name: c, group: 'c'},
]

新数据(来自 httpClient):

[ 
 0: {id: 1, name: a, group: 'b'},
 1: {id: 2, name: b, group: 'b'},
 2: {id: 3, name: c, group: 'c'},
]

在示例中,我想更新数组中的第一个对象,因为组字符串已更改,而不是替换整个对象数组。

我永远感激 why/how 的解决方案,而不仅仅是解决此问题的代码。 提前致谢!

*ngFor 可以利用 trackBy 函数将数组元素关联到 DOM 元素。这允许 angular 更有效地更新 DOM,因为它将不再销毁和重新创建所有项目,而只会创建新项目。

只需在您的控制器中创建一个小函数:

trackById = (index: number, item: Item) => item.id;

然后像这样将其添加到您的 *ngFor 中:

<div class="panels" *ngFor="let data of apiService.dataArray; trackBy: trackById">
    <div class="panel-that-has-animation">
        {{ data.some_value_that_can_be_updated }}
    </div>
</div>

现在您应该会看到,随着源数据的更改,只会创建新项目(动画),现有项目将保留。


另外,这不是你问题的一部分,但我想提一下你可以简化你的服务代码:

constructor(){
   this.getUpdateData();
   setInterval(()=> this.getUpdateData(), 1000);
}

getUpdateData(){
    this.httpClientCall()
    .subscribe((response: any) => {
      this.dataArray = response;
    });
  }

收件人:

dataArray$: Observable<Array<any>> = timer(0, 1000).pipe(
    switchMapTo(this.httpClientCall())
);

这有一个额外的好处就是懒惰;即 - 如果 dataArray$ 没有订阅者,您将不会轮询服务器。