Angular使用NGRX渲染表格时避免全表重绘,仅渲染变更行的解决方案
解决Angular表格修改行数据时整体重绘闪烁的问题
问题场景
我正在使用NgRx从远程API加载数据到数组,并将其渲染到传统HTML表格中。但遇到一个问题:当修改某一行数据(比如点击按钮修改数组中的某一行)时,整个表格会重新渲染,出现闪烁现象。我想知道是否可以配置Angular,让它只重新渲染数组中发生变更的行?
我的初始化代码:
ngOnInit() { this.store .select( createSelector( (state: AppState) => state.userProperties, (propObject: UserProperties) => propObject ) ) .pipe(takeUntil(this.destroyed$)) .subscribe(({properties, total }) => { this.propertyList = properties; this.totalFound = total; })
表格渲染代码:
<tbody> <ng-container *ngFor="let row of propertyList"> <tr> <td> </td> <td class="limited">{{ row.id }}</td> <td class="limited">{{ categoryLabels[row.category] | _: trans.lang }}</td> <td class="limited">{{ contractLabels[row.contract_type] | _: trans.lang }}</td> <td class="limited">{{ row.price }}</td> <td class="limited">{{ row.city }}</td> <td class="limited"> </td> <td> <div class="table-actions"> <button (click)="editProperty(row.id)" class="button button-icon"> <edit-icon></edit-icon> </button> <button *ngIf="row.deleted === 0" (click)="archiveProperty(row.id)" title="Delete this property" class="button button-icon"> <img src="/assets/images/icons/delete-red.svg" /> </button> <button (click)="toggleExpand(row.id)" class="button button-icon btn-expand"> <expand-icon [expanded]="expandedElements[row.id]"></expand-icon> </button> </div> </td> </tr> </ng-container>
解决方案(感谢@Dmytro Demyanenko)
要实现仅重新渲染变更的行,你需要给*ngFor指令添加trackBy属性:
修改后的ngFor代码:
<ng-container *ngFor="let row of propertyList; trackBy: trackByFn">
然后在组件类中定义trackByFn函数:
trackByFn(index, row) { return JSON.stringify(row); }
原理说明
Angular的*ngFor默认会通过对象引用或者索引来追踪元素是否需要重绘。当你从NgRx获取新的properties数组时,即使只有一行数据变化,整个数组的引用可能发生了改变,导致Angular重新渲染所有行。
而trackBy函数的作用是告诉Angular如何识别哪些元素是相同的:只有当trackBy函数返回的值与上次不同时,Angular才会重新渲染对应的行。这里我们返回row的JSON字符串,当行内任何数据发生变更时,这个字符串就会改变,从而触发该行的重新渲染,其他未变更的行则保持原样,避免了整个表格的闪烁问题。
内容的提问来源于stack exchange,提问作者albanx
相关产品推荐
相关产品推荐

