angular - 在 Angular 服务中按 id 缓存 RxJS 主题映射中的状态
问题描述
我为每个ownerId
. 我正在尝试通过使用Map<string, ReplaySubject<Widget[]>>
.
@Injectable({
providedIn: 'root',
})
export class WidgetService {
private readonly widgetsByOwnerId: Map<string, ReplaySubject<Widget[]>> =
new Map<string, ReplaySubject<Widget[]>>();
constructor(
private readonly httpClient: HttpClient
) {}
getWidgets(ownerId: string): Observable<Widget[]> {
if (!this.widgetsByOwnerId.has(ownerId)) {
const widgets$ = this.httpClient.get<Widget[]>(`api/${ownerId}/widgets`);
const widgetsCache$ = new ReplaySubject<Widget[]>(1);
widgets$.subscribe(widgetsCache$);
this.widgetsById.set(ownerId, widgetsCache$);
}
return this.widgetsById.get(ownerId).asObservable();
}
createWidget(widget: Widget): Observable<Widget> {
return this.httpClient
.post<Widget>(`api/${widget.ownerId}/widgets`, widget)
.pipe(
tap((createdWidget): void => {
this.widgetsByOwnerId.forEach((widgets$, ownerId) =>
widgets$.pipe(take(1)).subscribe({
next: (widgets: Widget[]) => {
if(createdWidget.ownerId == ownerId || isOwnedById) {
widgets.push(createdWidget);
widgets$.next(widgets);
}
},
})
);
}
);
}
//additional CRUD functions excluded for brevity
}
一些特殊类型的widget可以被多个widget所有者拥有,所以一些CRUD函数WidgetService
可以next()
放在multipleownerId
的ReplaySubject
s上。在上面的示例中,为了简洁起见,我省略了一些逻辑,使用isOwnedById
.
该服务的消费者如下所示:
@Component({
selector: 'app-widgets',
templateUrl: './widgets.component.html',
})
export class WidgetsComponent implements OnInit, OnDestroy {
widgets: Widget[];
private readonly ngUnsubscribe$: Subject<unknown> = new Subject();
constructor(
private readonly widgetService: WidgetService
) {}
ngOnInit(): void {
const ownerId = this.getOwnerId();
this.getWidgets(ownerId);
}
ngOnDestroy(): void {
this.ngUnsubscribe$.next();
this.ngUnsubscribe$.complete();
}
private getOwnerId(): string {
...
}
private getWidgets(ownerId: string): void {
this.widgetService
.getWidgets(ownerId)
.pipe(takeUntil(this.ngUnsubscribe$))
.subscribe({
// TODO: this next is called once when first subscribed, but not when future widgets are created
next: (widgets) => {
this.widgets = widgets;
},
});
}
}
由于某种原因,当消费组件第一次初始化时,它Widget[]
成功地获得了缓存。但是,当像在其他组件中执行的 CRUD 操作时WidgetService.createWidget()
(当实例WidgetComponent
保持活动状态时,例如 before WidgetComponent.ngOnDestroy()
),此WidgetComponent
使用者永远不会收到next()
-ed 更新(如注释中所述TODO
)。
关于如何解决这个问题的任何建议,以便消费者继续从WidgetService
s获取更新ReplaySubject
?谢谢。
这个问题与这个问题有点相似,但差异很大,以至于我无法弄清楚如何使他们的答案适应这个用例。
解决方案
我认为这里的主要问题是:
const widgets$ = this.httpClient.get<Widget[]>(`api/${ownerId}/widgets`);
const widgetsCache$ = new ReplaySubject<Widget[]>(1);
widgets$.subscribe(widgetsCache$);
httpClient
创建一个 finity Observable 意味着一旦请求完成或失败,它将完成。
结果,您ReplaySubject
传递的 as Observer
tosubscribe
方法将完成,您将不再收到任何事件。
要修复它,您可以将subscribe
实现替换为以下内容:
widgets$.subscribe(res => widgetsCache$.next(res));
推荐阅读
- reactjs - Mobx 存储方法在页面刷新时不起作用
- reactjs - 如何从对象数组中过滤具有相同标题的数据?
- excel - 具有来自同一列的多个 IF 标准的 AverageIFS
- angular - 如何在 Angular 单元测试中模拟 AWS 放大方法
- python - Flask Python 中的 KeyError
- java - org.flywaydb.core.internal.license.FlywayEnterpriseUpgradeRequiredException - ClassNotFoundException
- google-cloud-platform - 数据变化时查询
- javascript - 轮播项目位置每天都在变化!!(Django,实现)
- python - opencv中重叠圆圈之间的黑色区域 - python
- c# - 在 ASP.NET MVC 中将 10000 个数据上传到 Devextreme 数据网格时出现问题