首页 > 解决方案 > 使用 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 和 getEnigmaTransactions API 调用。但除此之外,我还需要在某些情况下手动触发 getEnigmaTransactions 调用,例如某些过滤条件发生变化时。

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

这样做的问题是,如果帐户发生更改,我需要取消现有的 combineLatest,否则它只会进行越来越多的订阅。所以我尝试放置一个 takeUntil ,每次帐户更改时都会取消,但我认为发生的事情是,一旦发出第一个 selectedAccount ,整个事情就会取消并且永远不会再次触发。

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

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

标签: angularrxjs

解决方案


永远不应该在 RXJS 中将 subscribe 放入 subscribe 中,您应该将传入的流合并为一个获取数据的流

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

  • combileLatest使得在任何输入数据发生变化时,
  • switchMap如果过滤器更改得更快以至于 API 可以返回数据,则将取消先前的请求。
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>

推荐阅读