Подписка вызывается слишком много раз после перенаправления маршрутизатора - PullRequest
0 голосов
/ 07 февраля 2019

У меня есть простой компонент, который выбирает что-то из состояния и прислушивается к изменению:

private items$: Observable<Item[]>;
private alive: boolean = true;

contructor(private store: Store<state>) {
  this.items$ = this.store.select(selectItems);
}

ngOnInit() {
  this.items$
    .pipe(
      takeWhile(() => this.alive)
    )
    .subscribe((items: Item[]) => {
      console.log('items changed!', items);
      // dispatch some actions
    });
}

ngOnDestroy() {
  this.alive = false;
}

Он работает отлично - каждый раз, когда элементы меняются, я вижу «элементы изменены!»строка записана.Когда я перенаправляю куда-то еще и компонент уничтожается, подписка не запускается.

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

Например, когда я вхожу на страницу:

items changed! null
items changed! ['a', 'b', 'c']
items changed! ['a', 'b', 'c', 'd']

Когда я перенаправляю и возвращаюсь к компоненту:

items changed! ['a', 'b', 'c', 'd']
items changed! ['a', 'b', 'c', 'd']
items changed! ['a', 'b', 'c', 'd']

Чтоздесь не так?Я пробовал takeUntil и тему, я пытался отписаться вручную - ничто не решает проблему.

Ответы [ 3 ]

0 голосов
/ 08 февраля 2019

Используйте takeUntil с темой

private items$: Observable<Item[]>;
private finalised = new Subject<void>();

contructor(private store: Store<state>) {
  this.items$ = this.store.select(selectItems);
}

ngOnInit() {
  this.items$
    .pipe(
      takeUntil(this.finalised)
    )
    .subscribe((items: Item[]) => {
      console.log('items changed!', items);
      // dispatch some actions
    });
}

ngOnDestroy() {
  this.finalised.next();
  this.finalised.complete();
}
0 голосов
/ 08 февраля 2019

Я думаю, что ваша проблема на самом деле в том, что вы не отмените подписку, когда компонент уничтожен.

Вы используете takeWhile, но этот оператор реагирует только тогда, когда его источник излучает.Это означает, что настройка this.alive = false; ничего не делает.Он может завершить цепочку, только если после этого испущено this.items$.Это будет поймано takeWhile, и это завершит цепочку.Но, вероятно, этого не происходит.

Рекомендуется использовать takeUntil или отписаться вручную.Это обсуждалось здесь много раз, и этот ответ должен сказать вам, что именно делать: Angular / RxJs Когда мне следует отписаться от `Subscription` .

0 голосов
/ 07 февраля 2019

Отмена подписки, или takeUntil будут выполнены после уничтожения компонента, а элементы будут изменены до уничтожения.

Вы получаете items changed! сообщение 3 раза, потому что в items$ есть 3 следующих события, поэтому подписчик был вызван 3раз.

Если вы хотите игнорировать события изменения с объектами так же, как в предыдущем событии, я предлагаю использовать оператор distinctUntilChanged.

Я буду выглядеть так:

items$
  .pipe(distinctUntilChanged((previous, current) => previous[0] === current[0] && ...)) /*
  .subscribe(items => console.log('items changed!', items));
  • DifferentUntilChanged имеет необязательный обратный вызов, но в вашем случае он вам понадобится, потому что по умолчанию используется (previous, current) => previous === current, а в случае массива строки ['a', 'b', 'c', 'd'] !== ['a', 'b', 'c', 'd'], поэтому вы должны написать функцию сравнения.

1020 * Docs *

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...