繁体   English   中英

Angular 8 订阅更新后触发

[英]Angular 8 subscribe fires after update

我想与多个组件共享一个 state(只是一个字符串)。 为此,我遇到了这个网站并将其实现到我的应用程序中,如下所示:

我的.component.ts

// ...
onButtonClick(event: MouseEvent) {
  console.log('1');
  this.myService.getStatus().subscribe(
    (currentStatus) => {
      console.log('2');
      if (currentStatus=== 'success') {
        // foo
      } else {
        // bar
      }
    },
    (error) => { /* ... */ },
    () => { /* ... */ }
  );
  console.log('3');
}
// ...

注意:我添加了 console.logs 进行调试。

这是我的服务

import { Injectable } from '@angular/core';
import { Subject, Observable } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class MyService {
  private status = new Subject<string>();

  constructor() { }

  getStatus(): Observable<string> {
    return this.status .asObservable();
  }

  updateStatus(updatedStatus: string) {
    this.status.next(updatedStatus);
  }
}

我现在的问题是,我不明白,为什么 subscribe() 在我用另一个按钮更新状态后被触发,所以调用堆栈类似于*Button Click* -> '1' -> '3' -> *btnUpdate click* -> '2' 我之前确实调用了 updateStatus() 来设置一个值。

我在同一个项目的其他地方使用了 observables,但它们的行为符合预期,与这个有什么不同?


编辑

这是给未来的读者的:参考Yevhenii Dovhaniuk 的回答,他让我对 Observables 有了更好的理解,他的回答也很有效

关于coldhot Observable 的定义,请访问官方文档了解更多详细信息。 简而言之,您的Subjectcold Observable 意味着每次您订阅它时都会执行它,并且如果没有订阅者活动 atm 将被销毁。

因此,要解决您的问题,请在构造函数中添加订阅,例如

export class MyService implements OnDestroy {
  private status = new Subject<string>();
  private statusSubjectSubscription: Subscription;

  constructor() { 
    this.statusSubjectSubscription = this.status.subscribe(); // here
  }

  ngOnDestroy() {
    if (this.statusSubjectSubscription) {
      this.statusSubjectSubscription.unsubscribe() // don't forget to unsubscribe
    }
  }

  getStatus(): Observable<string> {
    return this.status.asObservable();
  }

  updateStatus(updatedStatus: string) {
    this.status.next(updatedStatus);
  }
}

或将您的主题类型更改为 ReplaySubject 或 BehaviorSubject(请注意,行为可能会改变)

我不明白,为什么 subscribe() 在我用另一个按钮更新状态后被触发

因为您使用的是 rxJs Subject ,默认情况下不保存任何值,所以当您使用第一个按钮单击更新状态时,它不会保存该值,当您单击另一个按钮进行更新时,它会返回以前的值。 给你举个例子:

const subject = new Subject();
subject.next(1);
subject.subscribe(x => console.log(x));

这里控制台 output 将为空。 因此,要解决此问题,您可能需要使用最初保存一个值的BehaviorSubject ,因此当您订阅它时,它将立即返回该值。

在此处查看有关SubjectBehaviorSubject的更多详细信息。

要完成之前的答案,您需要取消订阅 Observable 以避免memory leaks

//Each time a subscribe is done, a Subscription is given in return
//Here your Subscription is lost leading to memory leak.
onButtonClick(event: MouseEvent) {
  this.myService.getStatus().subscribe(...);
}

最好在 ngOnInit 中订阅并将订阅存储在 class 属性中,该属性将在 ngOnDestroy 中销毁

ngOnInit(){
    this.subscription = this.myService.getStatus().subscribe(...);
}

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

我建议订阅您的 onInit 函数,因为订阅现在从您的按钮单击开始。 在下面的控制台日志之前没有时间完成,这反过来也会在 2 之前打印 1 -> 3。

最好的方法是退订。 访问以下链接

https://netbasal.com/when-to-unsubscribe-in-angular-d61c6b21bad3

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM