Angular 中的 Observable

Observables in Angular

我正在尝试使用 Observable 来观察另一个 class 内部特定变量的更新。 class A,这将是被观察的部分,看起来像这样:

currentSheetNumber = 0;

public updateSheetNumber(): any {
  const measurementDataObservable = new Observable(observer => {
    observer.next(this.currentSheetNumber);
  });
  return measurementDataObservable;
}

想看变化的ClassB的代码是这样的:

sheetNumberObserver;
sheetNumber: number = 0;

ngAfterViewInit(): void {
  this.sheetNumberObserver = this.measurementDataService.updateSheetNumber();
  this.sheetNumberObserver.subscribe((sheets) => {
    this.sheetNumber = sheets;
  });
}

不幸的是,当我更改 class A 中的值 currentSheetNumber 时,Class B 的值 sheetNumber 没有改变。

有人知道问题出在哪里吗?

正如@jonrsharpe 指出的那样,就目前的情况而言,您的可观察对象只会发出一个值。听起来您想要的是一种在 currentSheetNumber 发生变化时通知订阅者的方法。这是一种可能性,分两步进行。首先,按照@jonrsharpe 的建议,让我们从您的服务中公开一个 Subject(这是一种特殊的可观察对象):

public currentSheetNumber$ = new Subject();

然后,在class B:

ngAfterViewInit() {
  this.sheetNumberObserver = this.measurementDataService.currentSheetNumber$.subscribe((sheets) => {
    this.sheetNumber = sheets;
  });
}

此时,只要将值“添加”到 currentSheetNumber$ 主题,this.sheetNumber(在 class B 中)将相应更新。

但是,目前 currentSheetNumber$ 主题与您的 currentSheetNumber 变量(在您的服务中)没有任何关联。也就是说,当您更改 currentSheetNumber 时,currentSheetNumber$ 不会发生任何变化。我们需要将这两者“绑定”在一起,以便 currentSheetNumber 的更新由 currentSheetNumber$.

发出

实现此目的的一种方法是添加一种特殊方法来分配 currentSheetNumber,并且 使用该方法修改此变量。在这个方法中,我们可以同时更新 currentSheetNumber 向我们主题的订阅者发送新值:

setCurrentSheetNumber(value: number) {
  // Update the value of `currentSheetNumber`...
  this.currentSheetNumber = value;
  // ...and send the new value to subscribers of `currentSheetNumber$`
  this.currentSheetNumber$.emit(value);
}

这需要您将对 currentSheetNumber 的所有赋值替换为对 setCurrentSheetNumber.

的调用

这应该可行,但它涉及遵循我们无法强制执行的纪律(不对变量进行“直接”赋值)。这是 difficult-to-diagnose 错误的潜在来源。

幸运的是,有一种方法可以稍微调整当前设置以提供更多 fool-proof 体验。我们可以用一对“getter/setter”方法替换currentSheetNumber变量。这将允许我们在分配给 currentSheetNumber 时添加额外的“下一步”逻辑,而不必担心调用单独的方法:

get currentSheetNumber(): value {
  // What goes here?
}

set currentSheetNumber(value: number) {
  this.currentSheetNumber$.next(value);
}

现在,每当进行 this.currentSheetNumber = 42 之类的赋值时,新值(在本例中为 42)将发送给 currentSheetNumber$ 的所有订阅者。我们快到了。

我们需要解决的最后一个问题是:既然我们已经用 getter/setter 对替换了 currentSheetNumber,我们实际上在哪里 存储 价值?我们有几种选择。一种是添加另一个变量,比如 _currentSheetNumber,我们用它来维护当前值,但我们 从不直接与之交互 。看起来像这样:

_currentSheetNumber = 0;

get currentSheetNumber(): number {
  return this._currentSheetNumber;
}

set currentSheetNumber(value: number) {
  this._currentSheetNumber = value;
  this.currentSheetNumber$.next(value);
}

这不仅增加了我们现在需要考虑的额外变量,我们又回到必须遵守与以前类似的分配规则:我们需要永不直接分配给 _currentSheetNumber。必须有更好的方法。

有。我们需要做的就是使用 BehaviorSubject 而不是单纯的 SubjectBehaviorSubject 就像一个主题,但它“记住”了它的当前值,可以通过它的 getValue 方法访问它。这是它的样子:

public currentSheetNumber$ = new BehaviorSubject(0);

get currentSheetNumber(): number {
  return this.currentSheetNumber$.getValue();
}

set currentSheetNumber(value: number) {
  this.currentSheetNumber$.emit(value);
}

应该这样做,但是有一个重要的警告可能会导致错误和很多挫折。 BehaviorSubject 每当被订阅时都会发出其当前值。在许多情况下,这可能不是您想要的,并且它可能会迫使您添加一些错误(例如跳过订阅中的第一个发射值等)。在这种情况下,您最好使用 _currentSheetNumber 策略,尽管它有缺陷。

(或者,您可以 直接 currentSheetNumber$ 行为主体互动并避免这种喧嚣,编写一个保持其当前状态但不将其发送给新订阅者的自定义主题)