当我在获取数据后调度操作时无限循环 w/subscribe
infinite loop when i dispatch action after getting data w/subscribe
我是 angular 6 和 ngrx 商店的新人。我尝试在从商店获取数据订阅后发送操作,但它会造成无限循环并使浏览器崩溃?我错了什么。一些解决方案我发现它使用 rxjs 的 do/tap 运算符但仍然无法正常工作。例如,当我使用 {{(feedState | async).loading}} 时,它总是 return 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 => {});
}
select 运算符将创建一个可观察对象,它会在每次更新 '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 => {});
}
但是,可能值得考虑在此处拆分问题 - 您已将准备状态的工作与 select 显示状态的工作混合在一起。更好的解决方案可能是这样的:
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)。
我是 angular 6 和 ngrx 商店的新人。我尝试在从商店获取数据订阅后发送操作,但它会造成无限循环并使浏览器崩溃?我错了什么。一些解决方案我发现它使用 rxjs 的 do/tap 运算符但仍然无法正常工作。例如,当我使用 {{(feedState | async).loading}} 时,它总是 return 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 => {});
}
select 运算符将创建一个可观察对象,它会在每次更新 '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 => {});
}
但是,可能值得考虑在此处拆分问题 - 您已将准备状态的工作与 select 显示状态的工作混合在一起。更好的解决方案可能是这样的:
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)。