使用Rxjs构建Angular Store

问题描述

我有这个Angular应用,我想在其中创建聊天对象的自定义存储。

代码和框:https://codesandbox.io/s/chat-store-yw4yz

注意:我知道有类似ngrx的工具,但这是一个较大的项目的一部分,我希望使用此自定义实现,以便更好地了解商店的行为。

上下文

使其快速高效的想法是将两种类型的记录放入存储中:

  • 带有key = chat idvalue = chat object的字典(作为地图)
  • 用于按 groupId 分组聊天的索引(作为地图),其中key = groupIdvalue = chatId

所以我有这个接口定义:

export interface ChatStoreModel {
  chats: Map<number,Chat>;
  chatsByGroup: Map<number,number[]>;
}

将聊天对象保存到应用商店中时,应该发生两件事:

  • 聊天对象已保存到商店chats
  • 聊天ID被保存在相应的 groupId
  • 中的存储区chatsByGroup

问题

从群组中获取聊天对象不起作用。我执行以下操作:

  • 使用groupId从商店chatsByGroup获取聊天ID列表
  • 对于每个聊天ID,请从商店chats获取元素

代码

getGroupChats$(groupId: number): Observable<Chat[]> {
    return this._store.select("chatsByGroup").pipe(
      map((chatsByGroup) => chatsByGroup.get(groupId) || []),switchMap((ids) => {
        if (!ids || !ids.length) {
          return of([]);
        }
        const chatsList$: Observable<Chat>[] = ids.map((id) =>
          this._store.select("chats").pipe(map((chats) => chats.get(id)))
        );
        return forkJoin([...chatsList$]).pipe(
          map((list) => {
            return ([] as Chat[]).concat(...list);
          })
        );
      }),shareReplay(1)
    );
  }

调试此代码后,它到达return forkJoin行,并且id包含聊天列表,但它从未到达map((list) => {行,因此该应用程序不会显示聊天列表。

任何帮助将不胜感激,谢谢!

解决方法

只要可观察的任何一项完成而不产生任何价值, forkJoin也会在那一刻完成,并且不会发出 都可以

这来自RxJS ForkJoin Doc。我的猜测是,您传递给forkJoin的Observable之一没有发出任何东西而完成,因此forkJoin立即完成了而没有发出任何东西。

请尝试使用defaultIfEmpty运算符,以确保不会发生这种情况。我建议做这样的事情:

const chatsList$: Observable<Chat>[] = ids.map((id) =>
  this._store.select("chats").pipe(map((chats) => chats.get(id))),defaultIfEmpty(null),);

forkJoin将等待所有传递的可观察值完成

这也是来自文档。这意味着您传递给forkJoin的所有Observable必须完成,以使forkJoin自身发出价值。

我的猜测是,this._store.select("chats").pipe(map((chats) => chats.get(id))),这条线将无休止地运行,因此您需要提供take(1)才能完成,否则forkJoin将不会发出任何信息。所以尝试这样的事情:

const chatsList$: Observable<Chat>[] = ids.map((id) =>
  this._store.select("chats").pipe(map((chats) => chats.get(id))),take(1),);

最后,如果您不想使用take(1),这意味着您想订阅Observable,只要它发出值,您可能想要使用combineLatest而不是forkJoin。这是因为forkJoin等待完成发出某些东西,而combineLatest将发出所提供的Observable的最新值。