更新后Angular 8订阅触发

时间:2019-11-19 09:24:50

标签: angular angular8

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

my.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()来设置一个值。

我在同一项目的其他地方使用了可观测对象,但它们的行为符合预期,这有何不同?


修改

这是供将来的读者使用的: 请参阅answer of Yevhenii Dovhaniuk,他使我对Observables有了更好的理解,他的回答也很有效

4 个答案:

答案 0 :(得分:1)

涉及coldhot可观察对象的定义,有关更多详细信息,请访问官方文档。 简而言之,您的Subjectcold可观察的意思是,它将在您每次订阅时执行,如果没有活动的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);
  }
}

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

答案 1 :(得分:1)

  

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

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

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

此处控制台输出将为空。 因此,要解决此问题,您可能想使用最初拥有一个值的BehaviorSubject,因此,当您订阅它时,它将立即返回该值。

看看here有关SubjectBehaviorSubject的更多细节。

答案 2 :(得分:1)

要完成先前的答案,您需要取消订阅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并将Subscription存储在要在ngOnDestroy中销毁的类属性中

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

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

答案 3 :(得分:0)

我建议您使用onInit函数,因为现在单击按钮即可开始订阅。没有时间来完成下面的控制台日志,该控制台日志又在2之前打印1-> 3。