使用原始数组本身生成可观察数组

Generate Observable Array using the original Array itself

我有一个服务 (MessageService) 可以根据其他一些应用程序事件发出一些消息。
然后,我有一个组件 MessagesComponent,我想呈现我的服务发出的所有消息。我的方法是使用 Observable 来存储并在每次新消息到达时反应性地更新 UI 。 这是我的工作解决方案

@Component({
  selector: 'app-messages',
  template: `
    <h2>Received messages</h2>
    <ol>
      <li class="message" *ngFor="let message of messages$ | async">
        {{ message }}
      </li>
    </ol>
  `,
  styles: [``]
})
export class MessagesComponent implements OnInit, OnDestroy {
  destroy$ = new Subject<void>();
  messages$ = new BehaviorSubject<Message[]>([]);
  
  constructor(private messagesService: MessagesService) {}

  ngOnInit(): void {
    this.messagesService.message$
      .pipe(
        takeUntil(this.destroy$),
        switchMap((message: Message) =>
          this.messages$.pipe(
            take(1),
            map((all: Message[]) => {
              return [...all, message];
            })
          )
        )
      )
      .subscribe((messages: Message[]) => {
        this.messages$.next(messages);
      });
  }

  ngOnDestroy(): void {
    this.destroy$.next();
    this.destroy$.complete();
  }
}

现在,我从一个空的 BehaviorSubject 数组开始存储所有消息。然后,在 ngOnInit 挂钩中,我订阅了 MessagesService 的消息 $ 并且在新的发射之后我结合了我在 BehaviorSubject 与新消息一起发出一个包含所有项目的新数组。 我的解决方案似乎可行,但我想避免在 NgOnit 中进行订阅(如果可能)。我在想这样的事情

messages$: Observable<Message[]> = this.messagesService.message$.pipe(
        switchMap((message: Message) =>
          this.messages$.pipe(
            startWith([]),
            take(1),
            map((all: Message[]) => [...all, message])
          )
        )
      );

我正在尝试使用数组本身作为他们自己初始化的一部分,使用 SwitchMap + StartWith 但是它似乎没有工作,所以我正在寻找其他想法:)

哦,Message 类型只是一个带有一些属性的简单接口。

export interface Message {
  id: string;
  value: string;
}

您可以使用 scan 运算符来累积状态。它将可以访问之前的发射,您可以在此基础上进行构建。

export class AppComponent {
  
  messages$ = this.messagesService.message$.pipe(
    scan((all, message) => all.concat(message), [])
  );

  constructor(private messagesService: MessagesService) { }

}

scan收到来自mesageService.message$的发射时,它将运行函数

(all, message) => all.concat(message)

并发出结果。 message 是从服务接收到的值。第一次,all 的值是我们的初始种子值 ([])。之后就是之前发出的值;

注意组件代码已大大简化;您不需要:Subject、BehaviorSubject、subscription、ngOnInit、ngOnDestroy、takeUntil、switchMap,也不需要 :-)

这是一个小 StackBlitz 演示。