使用Rxjs(Angular)在几个不同的条件下刷新API调用



因此,要绘制图片,这是我当前的代码:

ngOnInit(): void {
this._pbsaAccountSelectorService.selectedAccount$.subscribe((pSelectedAccount) => {
this.getSelectedAccountData(this._pbsaAccountSelectorService.selectedProfile.ProfileId, pSelectedAccount.AccountNumberForRequests);
});
}
getSelectedAccountData(ProfileId: string, AccountNumberForRequests: string) {
if(!this._rewardsService.currentSpend) {
this._rewardsService.getCurrentSpend(ProfileId, AccountNumberForRequests).subscribe((res: any) => {
this._rewardsService.currentSpend = res
})
}
combineLatest([
this._rewardsService.getEnigmaTransactions(AccountNumberForRequests),
this.refresher$,
]).pipe(
map(([val]) => val),
takeUntil(this._pbsaAccountSelectorService.selectedAccount$),
).subscribe(res => {
this.transactionList = res;
this.filteredTransactionList = res;
})
}

预期的行为是,每当selectedAccount$Subject发出值时,它都会触发getCurrentSpend和getEnigmaTransactionsneneneba API调用。但除此之外,我还需要在某些情况下手动启动getEnigmaTransactions调用,比如一些过滤条件发生了变化。

为了实现这一点,我将getEnigmaTransactions调用放在带有复习主题的combineLatest中。

问题是,如果帐户发生更改,我需要取消现有的combineLatest,否则它只会进行越来越多的订阅。因此,我试图设置一个takeUntil,每次帐户更改时都会取消,但我认为发生的情况是,一旦发出第一个选定的帐户,整个操作就会取消,再也不会启动。

诚然,即使这个实现确实有效,我也可能会寻找一个更优雅的解决方案,因为这似乎是一种糟糕的做法。

我如何才能实现我想要的行为?也许使用SwitchMap?

您应该never在RXJS中将subscribe放入subscribe中,您应该将传入流合并为一个流,以获得您的数据

您应该将应该重新触发获取数据的所有内容都放入可观察的内容中,使其具有反应性。

  • combileLatest使得在改变任何输入数据时
  • 如果过滤器更改得更快,API可以返回数据,switchMap将取消以前的请求
class MyComponent {
readonly selectedAccount$ = new Subject<any>();
readonly filters$ = new Subject<any>();
readonly data$ = combineLatest([
this.selectedAccount$,
this.filters$
]).pipe(
switchMap(([account, filters]) => {
return fetchDataObservable(account, filters);
}),
//shareReplay({ refCount: true, bufferSize: 1 }), // If this observable would be used at multiple places this will prevent fetching data twice
//takeUntil(this.destroy), // If you would use this in other places than template only
);
}
<pre>{{data$ | async | json}}</pre>
  1. 嵌套订阅会导致嵌套数据流,而当组件被破坏时,嵌套数据流又会导致内存泄漏
  2. 使用switchMap从一个可观察到的对象映射到另一个
  3. 我认为这里使用combineLatest是多余的。如果getEnigmaTransactions()需要在两个单独的实例中触发,则将它们解耦。有两个单独的实例可以触发它

尝试以下

  • iif用于有条件地返回可观测
  • forkJoin并行触发多个可观测值
  • takeUntilSubject在组件关闭时关闭订阅
closed$ = new Subject<any>();
enigmaTransactions$ = (acctNum: any) => this._rewardsService.getEnigmaTransactions(acctNum);
ngOnInit() {
this._pbsaAccountSelectorService.selectedAccount$.pipe(
switchMap((pSelectedAccount: any) =>
iif(
() => (!this._rewardsService.currentSpend),
forkJoin({
currentSpend: this._rewardsService.getCurrentSpend(
this._pbsaAccountSelectorService.selectedProfile.ProfileId,
pSelectedAccount.AccountNumberForRequests
),
enigmaTransactions: this.enigmaTransactions$(
pSelectedAccount.AccountNumberForRequests
)
}),
this.getEnigmaTransactions$(
pSelectedAccount.AccountNumberForRequests
)
)
),
takeUntil(this.closed$)      // <-- close in `onDestroy` hook
).subscribe({
next: (res: any) => {
if (!!res.currentSpend) {  // <-- `forkJoin` was triggered
// do something
// res.currentSpend
// res.enigmaTransactions
} else {                   // <-- `forkJoin` was not triggered
// do something
}
},
error: (error: any) => {
// handle error
}
});
}
onFilterChange(acctNum: any) {
this.enigmaTransactions$(acctNum).pipe(
takeUntil(this.closed$)      // <-- close in `onDestroy` hook
).subscribe(
// handle response and error
);
}
ngOnDestroy() {
this.closed$.next();
}

最新更新