бесконечный цикл, когда я отправляю действие после получения данных с подпиской

Я новичок в магазине angular 6 и ngrx. Я пытаюсь отправить действие после получения подписки на данные из магазина, но он создает бесконечный цикл и вылетает из браузера? В чем я был не прав. Некоторое решение я нахожу с помощью оператора do / tap rxjs, но все еще не работает. И когда я, например, использую {{(feedState | async) .loading}}, он всегда возвращает значение undefined.

мой компонент:

  ngOnInit() {
    this.store.dispatch(new FeedActions.GetFeedCategories());
    this.feedSubscription = this.store
      .pipe(
        select('feed'),
        map(data => {
          this.feedState = data;
          return data.categories;
        }),
        tap(data =>
          this.store.dispatch(
            new FeedActions.GetFeedItems({
              cat_id: data[this.selectedIndex],
              page: 0
            })
          )
        )
      )
      .subscribe(data => {});
  }

person duy khanh    schedule 29.08.2018    source источник


Ответы (1)


Оператор select создаст наблюдаемый объект, который генерируется каждый раз при обновлении состояния 'feed'. Это сработает в первый раз, когда вы сделаете свой FeedActions.GetFeedCategories(), но он также сработает снова, когда результат FeedActions.GetFeedItems(...) будет добавлен к состоянию, что заставит FeedActions.GetFeedItmes(...) выполняться снова, и снова, и снова ...

Простое решение - добавить дубль (1) в канал, чтобы вы получили только один запуск карты и операторов касания:

ngOnInit() {
    this.store.dispatch(new FeedActions.GetFeedCategories());
    this.feedSubscription = this.store
      .pipe(
        select('feed'),
        take(1),
        map(data => {
          this.feedState = data;
          return data.categories;
        }),
        tap(data =>
          this.store.dispatch(
            new FeedActions.GetFeedItems({
              cat_id: data[this.selectedIndex],
              page: 0
            })
          )
        )
      )
      .subscribe(data => {});
  }

Однако, возможно, здесь стоит рассмотреть разделение проблем - вы смешали работу по подготовке состояния с работой по выбору состояния для отображения. Лучшее решение может быть примерно таким:

ngOnInit() {
    this.store.dispatch(new FeedActions.GetFeedCategories());
    this.store.pipe(
        select('feed'),
        take(1),
        map(data => data.categories),
        tap(data =>
          this.store.dispatch(
            new FeedActions.GetFeedItems({
              cat_id: data[this.selectedIndex],
              page: 0
            })
          )
        )
      )
      .subscribe(() => {});

      this.feedState = this.store.pipe(
          select('feed')
      );
  }

... тогда в вашем шаблоне вы можете использовать {{feedState | async}}?.loading или что-то еще по мере необходимости.

Канал async выполняет подписку за вас и ожидает наблюдаемого, а не необработанного поля данных. В вашем примере this.feedState должен иметь тип Observable<FeedState>, но он выглядит как необработанный тип данных (например, FeedState вместо Observable) из предоставленного кода.

person Mark Hughes    schedule 29.08.2018
comment
ой извините, я занят, я буду тестировать сейчас. Я пришел из React to angular, так что реактивный, это действительно странно. спасибо за помощь. : D - person duy khanh; 31.08.2018
comment
вау его работа как шарм. Я такой тупой, что мне нужно больше узнать о реактивном программировании: D Большое спасибо, счастливых выходных: D - person duy khanh; 31.08.2018
comment
Ой, подождите, а почему у вас есть символ? в {{feedState | async}} ?. loading :( Я не понимаю - person duy khanh; 31.08.2018
comment
Это нулевая проверка @duykhanh - это просто означает, что шаблон будет пустым, а не вызовет ошибку, если наблюдаемый объект испускает нуль или еще не отправил. - person Mark Hughes; 31.08.2018
comment
Спасибо @MarkHughes - ваше решение решает мою проблему! :) - person edi_smooth; 16.12.2019