使用原始数组本身生成可观察数组
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 演示。
我有一个服务 (MessageService) 可以根据其他一些应用程序事件发出一些消息。
然后,我有一个组件 MessagesComponent,我想呈现我的服务发出的所有消息。我的方法是使用 Observable
@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 演示。