因此,首先来介绍一下背景知识。我正在开发一个应用程序,正在使用agm地图来实时显示多个用户的位置。我最近一直在努力提高性能,因为可能有数千个用户,每个用户代表一个地图标记或dom元素。我已经将父组件和子组件更改为同时使用onpush策略,子组件使用ngFor循环呈现地图标记,我还将trackBy添加到此循环中。通过signalr接收位置更新,对象被正确更新,但即使在运行更改检测之后,标记在地图上的位置也没有被正确更新。
下面的两个组件是为了帮助识别问题而简化的版本。
首先是父Map组件
@Component({
selector: 'app-map',
template: '<agm-map>
<app-map-markers #mapMarkers [users]="users"></app-map-markers>
</agm-map>',
changeDetection: ChangeDetectionStrategy.OnPush
})
export class MapComponent implements OnInit, OnDestroy {
users: MapUser[];
private handleLocationUpdate(updatedUser: any) {
const user = this.users.find(this.findIndexToUpdate, updatedUser.Id);
if (user !== null && user !== undefined) {
user.lat = updatedUser.Lat;
user.lng = updatedUser.Lng;
user.lastSeen = updatedUser.LastSeen;
const userIndex = this.handledUsers.indexOf(user);
this.handledUsers[userIndex] = user;
}
}
findIndexToUpdate(newItem) {
return newItem.id === this;
}
}用户数组是通过对http服务的继承来填充的,但我省略了这一点,因为它工作得很好。当接收到位置更新时,它由父级处理,我离开了函数来显示这一点,但再次通过订阅signalr服务来调用该函数。
现在是地图标记组件。
@Component({
selector: 'app-map-markers',
template: '<agm-marker *ngFor="let user of users; let i = index; trackBy: trackByUser" [latitude]="user.lat" [longitude]="user.lng" [title]="user.firstName">
</agm-marker>',
changeDetection: ChangeDetectionStrategy.OnPush
})
export class MapMarkersComponent {
@Input() users: MapUser[];
constructor() {}
public trackByUser(indx: number, value: MapUser) {
let identifier: string = indx.toString();
if ('lat' in value && 'lng' in value) {
identifier = identifier.concat(value.lastSeen.toString());
}
return identifier;
}
}我怀疑问题是由于onpush没有检测到变化,然而出于性能原因,onpush似乎是这种情况下最好的策略。我只需要更新元素,而不是重新绘制整个用户列表。但也许我对angular还很陌生,所以我把我的电线都弄乱了。感谢您的帮助或建议。
发布于 2019-09-01 02:26:12
尝试调用更改检测'markForCheck()‘,这将使角度在下一个周期中运行更改检测。
@Component({
selector: 'app-map-markers',
template: '<agm-marker *ngFor="let user of users; let i = index; trackBy: trackByUser" [latitude]="user.lat" [longitude]="user.lng" [title]="user.firstName">
</agm-marker>',
changeDetection: ChangeDetectionStrategy.OnPush
})
export class MapMarkersComponent {
public users: MapUser[]
@Input()
set users(values: any[]){
this.users = values;
this.cdr.markForCheck();
}
constructor(private cdr: changeDetectorRef) {}
public trackByUser(indx: number, value: MapUser) {
let identifier: string = indx.toString();
if ('lat' in value && 'lng' in value) {
identifier = identifier.concat(value.lastSeen.toString());
}
return identifier;
}
}https://stackoverflow.com/questions/57740459
复制相似问题