RxJS渲染完成后如何从Observable中删除元素
问题描述
从后端获取条目并在表格展示,点击按钮删除条目时,需先在服务器端删除,同时同步更新UI,但不想重新加载所有后端条目,而是直接从渲染表格的模型(entries$)中移除已删除条目。
尝试的代码如下:
deleteEntrySubject = new BehaviorSubject<any>(null); deletedEntry$ = this.deleteEntrySubject.asObservable(); //.pipe(switchMap(e => this.entryService.delete(e))); entries$ = combineLatest([ of([ { n: '1', id: 1 }, { n: '2', id: 2 }, ]), this.deletedEntry$, ]).pipe( filter(([entries, deletedEntry]) => deletedEntry !== null), map(([entries, deletedEntry]) => entries.filter((entry) => entry.id !== deletedEntry?.id) ) ) .subscribe((result) => console.log('res', result)); deleteEntry(id) { this.deleteEntrySubject.next({ n: id, id: id }); }
这段代码初期运行正常,但由于初始Observable(此处由of()提供)未发生变化,每次删除都会基于初始的两个值重新计算。例如删除条目1后结果只剩条目2,再删除条目2时,结果又会出现已删除的条目1。
希望用RxJS的正确方式实现需求,且无需借助组件状态记录已删除的条目。
解决方案
核心问题是每次都基于初始的完整条目列表做过滤,没有保留之前删除操作后的状态。用scan操作符可以维护状态,累积每次操作的结果,完美解决这个问题。
修改后的代码示例:
deleteEntrySubject = new BehaviorSubject<number | null>(null); deletedEntry$ = this.deleteEntrySubject.asObservable(); // 模拟从后端获取初始条目 const initialEntries$ = of([ { n: '1', id: 1 }, { n: '2', id: 2 }, ]); entries$ = initialEntries$.pipe( // 先获取初始条目,再监听后续删除事件 mergeMap(initialEntries => this.deletedEntry$.pipe( // 用scan累积状态:每次删除都基于当前列表过滤 scan((currentEntries, deletedId) => { if (deletedId === null) return currentEntries; return currentEntries.filter(entry => entry.id !== deletedId); }, initialEntries), // 跳过BehaviorSubject初始的null值 skip(1) ) ), // 订阅时先输出初始条目 startWith(initialEntries$) ); deleteEntry(id: number) { // 优先调用后端删除接口 this.entryService.delete(id).subscribe(() => { // 后端删除成功后,通知前端更新状态 this.deleteEntrySubject.next(id); }); }
关键细节:
scan操作符:负责维护当前的条目列表状态,每次收到删除ID时,基于上一次的列表结果过滤掉对应条目,而非回到初始列表重新计算。mergeMap嵌套:确保初始条目仅加载一次,后续只处理删除事件。- 后端操作前置:先完成服务器端删除,再更新前端状态,避免前端删除后后端操作失败导致数据不一致。
- 跳过初始null:
BehaviorSubject初始值为null,用skip(1)跳过第一次无意义的计算,直接从初始条目开始输出。
这样就能实现每次删除后UI基于最新状态更新,不会重复出现已删除条目,也不需要额外组件状态记录删除历史。
内容的提问来源于stack exchange,提问作者Sebastian
相关产品推荐
相关产品推荐

