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 使用新数组实例更新时都会重新创建这些组件。