Angular:在没有内存泄漏的情况下对不相关组件之间的通信感到困惑

Angular: Confused over communicating between unrelated components without a memory leak

据我所知,不相关的 Angular 组件进行通信的首选方式是创建服务并使用 RxJS BehaviorSubject。这是我发现的关于这种方法的众多在线参考之一:

https://fireship.io/lessons/sharing-data-between-angular-components-four-methods/

对于不相关的组件,本站和其他网站一样,提倡在服务中做类似以下的事情:

private messageSource = new BehaviorSubject('default message');
currentMessage = this.messageSource.asObservable();

changeMessage(message: string) {
     this.messageSource.next(message)
}

然后,在另一个组件中:

ngOnInit() {
     this.data.currentMessage.subscribe(message => this.message = message)
}

这种方式非常简单,我能够使用这种方式共享数据。然而,在我读到的每一篇关于订阅的参考资料中,他们都说取消订阅以避免内存泄漏很重要。似乎没有办法使用这种方法取消订阅。在使用这种方法时,是否有我误解或需要一些额外的步骤来避免内存泄漏?有什么我应该改用的方法吗?

您可以取消订阅组件的 onDestroy 生命周期钩子。

subscription: Subscription

ngOnInit() {
 this.data.currentMessage.subscribe(message => this.message = message)
}

ngOnDestroy() {
 this.subscription.unsubscribe();
}

这意味着这个特定组件在销毁时将取消订阅行为主题。

您可以在组件 ngOnDestroy 方法中轻松取消订阅:

OtherComponent implements OnInit, OnDestroy {

  private subscription: Subscription;

  //...

  ngOnInit() {
    this.subscription = this.data.currentMessage.subscribe(
      message => this.message = message
    );
  }

  ngOnDestroy() {
    this.subscription.unsubscribe();
  }
}

或者,您可以使用 RxJs takeWhile 和您发出的带有销毁值的主题做一些有趣的事情。

您可以在 this blog post on Medium 中找到该解决方案和其他很好的示例。

我的两分钱:

我喜欢 Wilt link 中提到的 takeUntil 技术(尽管他不小心提到了 takeWhile)。如果您喜欢使用继承,我有一个 class 仅用于处理此问题,然后任何可能需要自动取消订阅的组件都继承自它。它看起来像这样:

export class Unsubscriber implements OnDestroy {

    unsubscribe$: Subject<void> = new Subject()

    constructor() {}

    ngOnDestroy() {
         this.unsubscribe$.next();
         this.unsubscribe$.complete();
    }
}

然后在您的组件中扩展 class,确保每次订阅时添加以下内容:

.pipe(takeUntil(this.unsubscribe$))

所以对于你的 class:

export class MyClass extends Unsubscriber implements OnInit, OnDestroy {

  //...

    ngOnInit() {
        this.data.currentMessage.pipe(takeUntil(this.unsubscribe$)).subscribe(message => this.message = message);
    }
}

我喜欢这个,因为无论您的组件当前有多少订阅,它都会起作用。唯一的烦恼是记住要始终添加该管道,尽管这不是什么可怕的负担,即使在现有项目上修复也不是太难。