Angular/RXJS:从可观察对象更改对象的值会更改其在 BehaviorSubject 中的值

Angular/RXJS: Changing values of an object from an observable changes its value in the BehaviorSubject

这很奇怪...我有一个单例(providedIn:“root”)服务,它有一个 BehaviorSubject,它是私有的,但作​​为一个可观察对象公开:

private readonly _caseData$ = new BehaviorSubject<CaseData | null>(null);
Context = this.caseData$.asObservable();

上下文由另一个函数设置,该函数在主题上调用 next,然后从上下文中检索值。

在一个组件中,我有一个函数接受一个值,然后从 Context 中通过管道从 CaseData 上的数组中删除一些值,并调用服务中的另一个函数:

unassign = (tag: Tag) => {
  this.caseContext.Context.pipe(
    switchMap((caseData) => {
      const index = caseData.tags.findIndex(tagId => tagId === tag.tagId);
      if (index > -1) {
        caseData.tags.splice(index, 1);
      }
      return of(caseData);
    }),
    concatMap((caseData: CaseData) => {
      return this.caseContext.patchCase(caseData);
    })
  )
}

这很好用,但是当我调用 patchCase 并订阅该函数中的行为主题时,它发生了变化。在上面的 switchMap 中删除的标签在行为主题中的 CaseData 中也被删除。

public patchCase(updated: CaseData): Observable<CaseData> {
    return of(updated).pipe(
      mergeMap((changed: CaseData) => {
        return combineLatest([this._caseData$, of(changed)]);
      }),
      map(([original, changed]: [CaseData, CaseData]) => { 
            ^- this value has the tags removed that were removed in the previous function.      
        return {
          caseId: changed.caseId,
          operations: createPatch(original, changed)
        };
      }),
      concatMap((caseOperations: { caseId: string; operations: Operation[] }) => {
        return this._caseApi.patch(caseOperations.caseId, caseOperations.operations);
      }),
      tap((updated: CaseData) => {
        this.load(updated.caseId);
      })
    );
  }

我确信有比我上面的更好的方法来构建整个事情,我可以通过在删除标签之前在取消分配函数中复制对象来解决这个问题,但是为什么当我在另一个可观察流中更改它时,案例数据会发生变化吗?如果这是预期的,除了制作副本之外,是否有更好的方法来做这种事情而不改变主题中的值?

因为这条线发生了

caseData.tags.splice(index, 1);

在这种情况下 .tags 数组发生了变异。要摆脱它,请尝试像这样修改您的代码:

unassign = (tag: Tag) => {
  this.caseContext.Context.pipe(
    map((caseData) => ({
      ...caseData,
      tags: caseData.tags.filter(tagId => tagId !== tag.tagId)
    })),
    concatMap((caseData: CaseData) => {
      return this.caseContext.patchCase(caseData);
    })
  )
}

switchMap 在这里没用,因为您基本上是将简单值映射到简单值,而不是可观察值。