Angular: наблюдаемая подписка в сервисе - использование его с ngOnChanges запускается (слишком) много раз - PullRequest
0 голосов
/ 29 мая 2018

поэтому у меня есть такой сценарий (просто)

  • основной компонент
  • компонент списка
  • служба списка

где:

основной компонент

<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 get вызывается много, много раз ... даже если я изменяю только значение месяца1.

Как упорядочить вещи, которые getAllByMonth получает, называемые ONCE, когда меняется значение месяца?

1 Ответ

0 голосов
/ 29 мая 2018

*ngFor использует сравнение равно ===, чтобы увидеть, изменился ли экземпляр Array.Если новый массив и старый массив не являются одной и той же ссылкой, то все элементы в коллекции воссоздаются.

Чтобы сообщить *ngFor, что он не должен воссоздавать элемент, но повторно использовать элемент вмассив.Вы должны использовать функцию обратного вызова trackBy.

<li *ngFor="let item in list | async; trackBy: trackItem"></li>

Затем в вашем компоненте

public trackItem(indx: number, item: LinkItem): number {
     return item.id;
}

Эта функция должна возвращать значение (число, строку, объект и т. Д.), Котороедает true для равных === сравнений.Вот как ngFor знает, что он должен повторно использовать компонент с этим элементом массива.

В моем примере выше я предположил, что это уникальный номер id, который можно использовать из каждого LinkItem.

Все это останавливает рекурсивные вызовы ngOnChanges, поскольку эти компоненты воссоздаются каждый раз, когда list обновляется новым экземпляром массива.

...