BehaviorSubject 和 concatMap 的副作用

Side effects with BehaviorSubject and concatMap

这是我第一次尝试使用 BehaviorSubject、异步管道和 concatMap,所以我在 DOM.

中更新数据时遇到了一些问题

我有:

private profilesStore = new BehaviorSubject<any>(null);
profiles$ = this.profilesStore.asObservable();

  getUserProfiles(): Observable<Profile[]> {
    const headers = this.authService.getHeaders();
    return this.http.get<any>(`${API_URL}/profile`, { headers: headers })
      .pipe(
        catchError(err => throwError(err)),
        tap(res => this.profilesStore.next(res)),
        shareReplay()
      );
  }

然后

addProduct(profileId: any) {
    const headers = this.authService.getHeaders();
    return this.http.post<any>(`${apiUrl}/products/${profileId}`, {}, { headers: headers })
      .pipe(
        catchError(err => throwError(err)),
        concatMap(() => this.profileService.profiles$),
        map(profiles => {
          const selectedProfile = profiles.findIndex(profile => profile.id === profileId);
            profiles[selectedProfile].canEdit = true;
            return profiles;
        })
      );
  }

这个逻辑就像购物车逻辑。我将产品添加到其中一个配置文件,以避免再次调用 api (getUserProfiles) 我修改了 profiles$ 流并添加了我想要的 属性(在本例中为 canEdit),但问题来了当我从购物车中删除产品并从 getUserProfiles() 恢复数据时,我知道当我将 concatMap 与 profiles$ 一起使用时,即使我没有调用该函数,我也会对 addProduct() 产生副作用,我的问题是......

为什么它会继续执行

map(profiles => {
          const selectedProfile = profiles.findIndex(profile => profile.id === profileId);
          profiles[selectedProfile].canEdit = true;
            return profiles;
        })

使用我过去作为参数传递的旧 profileId,即使我没有调用 addProduct() 函数,如何避免这种情况?

将可观察对象想象成一个水龙头,一旦您订阅它,水龙头就永远不会关闭。只要有水,水就会一直流。只有当您取消订阅(或任何其他结束它的运营商)时,点击才会关闭。

所以当你做一个addProfile()的那一刻,即使只是一次,它的可观察性永远打开,只要有数据(水)的排放,数据的排放就会继续,即使你不再调用函数 addProfile() -> 而且,如果你调用函数两次,你实际上有两个订阅,也就是两个水管和水龙头;这是大多数开发人员没有注意的事情。

因此,当您第一次拨打 addProfile() 并且您从未取消订阅时,由于

,您实际上转而收听 profiles$
  concatMap(() => this.profileService.profiles$),

,你的数据流实际上开始监听那个 BehaviourSubject 的变化,这就解释了即使你不再调用 addProfile(),但是因为你更新了你的 profiles$,发射仍然通过,数据流将流经管道,然后将有效执行下一个管道操作符:

map(profiles => {
          const selectedProfile = profiles.findIndex(profile => profile.id === profileId);
          profiles[selectedProfile].canEdit = true;
            return profiles;
        })