【发布时间】:2022-10-21 19:37:28
【问题描述】:
我正在使用 ngRxStore 处理 Angular 13 项目,在我的组件中,我有以下代码:
enterpriseState$: Observable<EnterpriseState> | null = null;
exporter$: Observable<ExporterDTO> | null = null;
readonly exporterStateEnum = EnterpriseStateEnum;
ngOnInit(): void {
this.enterpriseState$ = this.store.pipe(
map((state) => state.myStateModule.enterpriseState)
);
if (this.enterpriseState$) {
this.enterpriseState$.subscribe((state: EnterpriseState) => {
if (state && state.dataState === EnterpriseStateEnum.LOADED) {
console.log(' subscribe enterpriseeeee LOADED'); // this log is called 5 times
// And this http request is called 5 times too
this.exporter$ = this.myService.getEnterprise(state.exporter?.identifier).pipe(shareReplay(1));
}
});
}
}
//this is my stated object
export interface EnterpriseState {
exporter: EnterpriseDTO,
errorMessage: string,
dataState: EnterpriseStateEnum
}
问题是我的订阅被调用了 5 次,并且多次触发了 http 请求。
你知道我的代码有什么问题以及如何避免多次调用。 我已经尝试过运营商skip and take,但它没有用。
【问题讨论】:
-
是的,你有内存泄漏。试试这个:
this.enterpriseState$ = this.store.pipe(first(), map((state) => state.myStateModule.enterpriseState));。您还可以删除您的 if 检查,因为它是多余的,并且只会添加额外的嵌套级别if (this.enterpriseState$) -
如果您的组件处理此
enterpriseState的多个状态更改,并且它必须在其生命周期内对这些更改做出反应,那么实现OnDestroy并取消订阅连接到ngrx 状态的所有可观察对象。 -
然后删除
first并将订阅的引用存储为组件中的私有字段。在组件中实现OnDestroy接口并在ngOnDestroy生命周期挂钩内取消订阅。 -
当您使用
map运算符时,即使您的“映射值”没有更改,您的 observable 也可能会发出。因此,您应该使用store.select()而不是store.pipe(map(...))。在您当前的代码中,尝试在 map 运算符后添加tap(val => console.log(val))并查看是否重复发出相同的值,或者每次的值是否不同。如果值相同,切换到store.select()可能会解决您的问题。 -
@BizzyBob 非常感谢您的建议,我会尝试并与您保持联系