我为每个 ownerId
收集了一个小部件.我正在尝试使用 Map<string, ReplaySubject<Widget[]>>
在 Angular 服务中缓存这些集合的状态.
@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
}
某些特殊类型的小部件可以由多个小部件所有者拥有,因此 WidgetService
中的一些 CRUD 功能可以next()
在多个 ownerId
的 ReplaySubject
秒。在上面的示例中,为了简洁起见,我使用 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[]
成功地。但是,当像 WidgetService.createWidget()
这样的 CRUD 操作时在其他组件中执行(同时 WidgetComponent
的实例仍然存在,例如在 WidgetComponent.ngOnDestroy()
之前),这个 WidgetComponent
消费者永远不会收到 next()
-ed 更新(如 TODO
评论中所述)。
有关如何解决此问题的任何建议,以便消费者继续从 WidgetService
获得更新的 ReplaySubject
秒?谢谢。
这个问题有点类似于this one ,但差异很大,以至于我无法弄清楚如何使他们的答案适应这个用例。
最佳答案
我认为这里的主要问题在于:
const widgets$ = this.httpClient.get<Widget[]>(`api/${ownerId}/widgets`);
const widgetsCache$ = new ReplaySubject<Widget[]>(1);
widgets$.subscribe(widgetsCache$);
httpClient
创建一个有限的 Observable,这意味着一旦请求完成或失败,它就会完成。
因此,您的 ReplaySubject
作为 Observer
传递给 subscribe
方法将完成,您将不会再收到任何事件。
要修复它,您可以将 subscribe
实现替换为以下内容:
widgets$.subscribe(res => widgetsCache$.next(res));
关于angular - 在 Angular 服务中通过 id 在 RxJS Subjects Map 中缓存状态,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61737059/