Angular:服务中的 Observable 订阅 - 将其与 ngOnChanges 一起运行(太多)次
Angular: Observable subscribing in service - using it with ngOnChanges runs (too) many times
所以我有这样的场景(简单化)
- 主要成分
- 列表组件
- 列出服务
其中:
主要成分
<my-list [month]="month"></my-list>
列表组件html
<li *ngFor="let item in list | async></li>
列出组件 ts
list: Observable<ListItem[]>;
@Input() month: string;
...
ngOnInit() {
this.list = this._listService.list;
}
ngOnChanges(changes: SimpleChanges) {
if (changes.month && !!this.month) {
this._listService.getAllByMonth(this.month);
}
}
最后列出服务
private _list: BehaviorSubject<ListItem[]>;
list: Observable<ListItem[]>;
private dataStore: {
list: ListItem[]
};
constructor(private _http: HttpClient) {
this.dataStore = { list: [] };
this._list= <BehaviorSubject<ListItem[]>>new BehaviorSubject([]);
this.list= this._list.asObservable();
}
public getAllByMonth(month: string) {
this._http.get<ListItem[]>(environment.apiPath + 'list/' + month)
.subscribe(
data => {
this.dataStore.list = data;
this._list.next(Object.assign({}, this.dataStore).list);
},
error => console.log('Could not load the list.')
);
}
出于某种原因,getAllByMonth 被调用了很多很多次...即使我只更改了月份值 1。
当月份值发生变化时,应该如何安排 getAllByMonth 调用 ONCE 的事情?
*ngFor
使用等于 ===
比较来查看 Array
实例是否已更改。当新数组和旧数组不是同一个引用时,则重新创建集合中的所有元素。
告诉*ngFor
它不应该重新创建一个元素,而是重新使用数组中的一个元素。您必须使用 trackBy
回调函数。
<li *ngFor="let item in list | async; trackBy: trackItem"></li>
然后在你的组件中
public trackItem(indx: number, item: LinkItem): number {
return item.id;
}
此函数需要 return 一个值(数字、字符串、对象等)产生 true
以进行相等 ===
比较。这就是 ngFor
知道它应该重新使用具有该数组项的组件的方式。
在我上面的例子中,我假设它们是一个唯一的数字 id
,可以从每个 LinkItem
.
中使用
所有这些都停止了对 ngOnChanges
的递归调用,因为每次 list
使用新数组实例更新时都会重新创建这些组件。
所以我有这样的场景(简单化)
- 主要成分
- 列表组件
- 列出服务
其中:
主要成分
<my-list [month]="month"></my-list>
列表组件html
<li *ngFor="let item in list | async></li>
列出组件 ts
list: Observable<ListItem[]>;
@Input() month: string;
...
ngOnInit() {
this.list = this._listService.list;
}
ngOnChanges(changes: SimpleChanges) {
if (changes.month && !!this.month) {
this._listService.getAllByMonth(this.month);
}
}
最后列出服务
private _list: BehaviorSubject<ListItem[]>;
list: Observable<ListItem[]>;
private dataStore: {
list: ListItem[]
};
constructor(private _http: HttpClient) {
this.dataStore = { list: [] };
this._list= <BehaviorSubject<ListItem[]>>new BehaviorSubject([]);
this.list= this._list.asObservable();
}
public getAllByMonth(month: string) {
this._http.get<ListItem[]>(environment.apiPath + 'list/' + month)
.subscribe(
data => {
this.dataStore.list = data;
this._list.next(Object.assign({}, this.dataStore).list);
},
error => console.log('Could not load the list.')
);
}
出于某种原因,getAllByMonth 被调用了很多很多次...即使我只更改了月份值 1。
当月份值发生变化时,应该如何安排 getAllByMonth 调用 ONCE 的事情?
*ngFor
使用等于 ===
比较来查看 Array
实例是否已更改。当新数组和旧数组不是同一个引用时,则重新创建集合中的所有元素。
告诉*ngFor
它不应该重新创建一个元素,而是重新使用数组中的一个元素。您必须使用 trackBy
回调函数。
<li *ngFor="let item in list | async; trackBy: trackItem"></li>
然后在你的组件中
public trackItem(indx: number, item: LinkItem): number {
return item.id;
}
此函数需要 return 一个值(数字、字符串、对象等)产生 true
以进行相等 ===
比较。这就是 ngFor
知道它应该重新使用具有该数组项的组件的方式。
在我上面的例子中,我假设它们是一个唯一的数字 id
,可以从每个 LinkItem
.
所有这些都停止了对 ngOnChanges
的递归调用,因为每次 list
使用新数组实例更新时都会重新创建这些组件。