当我在获取数据w / subscribe后调度动作时出现无限循环

时间:2018-08-29 08:21:52

标签: angular6 ngrx-store rxjs6

我是angular 6和ngrx存储中的新手。我尝试从存储中获取数据订阅后调度操作,但它会导致无限循环并导致浏览器崩溃?我错了。我使用rxjs的do / tap运算符找到了一些解决方案,但仍然无法正常工作。例如,当我使用{{(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 => {});
  }

1 个答案:

答案 0 :(得分:3)

select运算符将创建一个observable,每次“ feed”的状态更新时都会发出该观测值。这将在您执行FeedActions.GetFeedCategories()时第一次触发,但是在将FeedActions.GetFeedItems(...)的结果添加到状态时也会再次触发,这将导致再次执行FeedActions.GetFeedItmes(...),并且一次又一次...

简单的解决方案是在管道中添加take(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)。