组件销毁并重新访问后,订阅在 ngOnInit 函数中运行

Subscription runs in ngOnInit function after Component is destroyed and Revisited

我 运行 使用 Angular 组件和 rxjs 订阅时遇到了一个非常奇怪的情况。

我有以下 ngOnInitngOnDestroy 函数

ngOnInit() {
    zip(this.service.getMessage, this.service.getType)
      .pipe(takeUntil(this.componentDestroyed$))
      .subscribe(data => {
        const notification = new Notification(data[0], data[1]);
        this.notifications.push(notification);
    });
}

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

在如下所示的服务文件中使用源和主题范例设置值后订阅处于活动状态:

private messageSource = new BehaviorSubject<string>('');
private message = this.messageSource.asObservable();
private typeSource = new BehaviorSubject<number>(-1);
private type = this.typeSource.asObservable();

...
...

set setMessage(message: string) {
  this.messageSource.next(message);
}

set setType(type: number) {
  this.typeSource.next(type);
}

初始订阅工作正常,符合预期。但是,离开组件并导航回同一组件会在 ngOnInit 中再次运行 zip 订阅,即使在离开时组件已被销毁后也是如此。如何防止这种情况发生?我还尝试定义一个订阅变量并调用 unsubscribe。我被难住了。

为了扩展我的评论,BehaviorSubject 上的 RxJS BehaviorSubjects hold the current value pushed to it and emit it immediately upon subscription. It also allows you to use the unique getValue() function (or value getter) 允许您同步检索它持有的当前值。虽然这个 getter 的用法通常不受欢迎。

因此,在您的情况下,当您路由回组件时,订阅会发出两个 observable 先前持有的值。相反,您可以使用 RxJS Subject not 保存值并仅在将值推送给它后才发出。

private messageSource = new Subject<string>();
private message = this.messageSource.asObservable();
private typeSource = new Subject<number>();
private type = this.typeSource.asObservable();
...

我还建议您看看 RxJS ReplaySubject。它是一个更灵活的多播可观察对象。它接受要缓冲的通知数量并在新订阅时立即发出它们。

所以 ReplaySubject(1)(缓冲区 1)类似于 BehaviorSubject,只是它不需要默认值。因此,如果您在尚未向其中推送任何内容时订阅它,它就不会发出。

它对解决当前问题没有帮助,但在您希望具有 BehaviorSubject 的行为但不希望处理不必要的默认值时可能会有所帮助.