BehaviorSubject .next() 没有发出更新的值

BehaviorSubject .next() is not emitting updated value

我只是想为我对 RxJS 和 Observables 的缺乏理解而道歉。我之前发布了一个问题,但它的措辞很糟糕,我知道它无法理解,所以一天后我想我可以更好地解释我的问题。

  1. 我的代码的 objective 是获取用户输入,将其作为动作流传递到我的数据流,将输入与我的托架数组进行比较,如果存在,return单湾。如果它不存在 (这是我挣扎的地方) return 我可以在我的 bay.page.ts 中回调并检查它是否truefalse。如果是 false [显示客户端错误]。 如果是 true,请向前导航至结果页面。
  2. 我的 bay-service.ts class 包含我的数据和操作流:
export class BayServiceService {
  private baysUrl = 'api/bays';

  bays$ = this.http.get<Bay[]>(this.baysUrl)
    .pipe(
      tap(data => console.log('Bays: ', JSON.stringify(data))),
      catchError(this.handleError)
    );

  /*--------------------------------------------------------------*/
  // Grab A Single Bay
  private baySelectedSubject = new BehaviorSubject<number>(0);
  baySelectedAction$ = this.baySelectedSubject.asObservable();

  invalidBay = new BehaviorSubject<boolean>(false);

  selectedBay$ = combineLatest([
    this.bays$,
    this.baySelectedAction$
  ])
    .pipe(
      map(([bays, selectedBayNumber]) => {
        if (!bays.find(bay => bay.bayCode === selectedBayNumber)){
          this.invalidBay.next(false);
        } else {
          this.invalidBay.next(true);
          return bays.find(bay => bay.bayCode === selectedBayNumber);
        }
      }),
      );

  selectedBayChanged(selectedBayNumber: number): void {
    this.baySelectedSubject.next(selectedBayNumber);
  }

^ 在上面的代码中,我使用了一种声明式 RxJS 方法 selectedBay$,其中我结合了我的 bay$ 数据流和我的 baySelectedAction$ 动作流(其中包含用户输入) .然后我映射它们,然后将用户输入 selectedBayNumber 与单个托架编号进行比较。

问题: 我正在尝试使用我在 bay-service.ts 中创建的 Observable -> invalidBay = new BehaviorSubject<boolean>(false); 并检查它的结果:如果它是真的, 向前导航。如果它是 false,则显示它不存在的客户端错误。 但是,如果用户输入有效的托架编号,我尝试通过 this.invalidBay.next(true); 将 Observable 更改为 true 但是,Observable 不会更新它的值? BehaviorObservable 保持其默认值 'false'。所以代码部分有效,但不是完全有效。

  1. 这是我 bay-page.ts 中的 onSubmit 方法,我在其中处理我的操作流的用户输入。我将用户输入传递给一个方法(在我的 bay-service.ts class 中)。根据他们的输入,我尝试订阅“应该更新”的 Observable,然后从那里开始。但是 Observable 没有被更新。请帮助。
onSubmit() {
    this.bayService.selectedBayChanged(this.bayForm.get('bayStart').value);
    this.subscription = this.bayService.invalidBay.subscribe(value => {
        if (value) {
            this.navCtrl.navigateForward([`/results/`]);
        } else {
            this.bayDoesNotExistError = true;
            this.selectedBay = this.bayForm.get('bayStart').value;
            this.vibration.vibrate(500);
            console.log('Vibrating for 3 second...')
        }
    })
}

为什么 Observable 没有更新它的值?拜托,我的心很痛,我不知道还能做什么。

如果没有观察者订阅,则 Observable 不执行任何操作。您没有订阅 selectedBay$ 可观察对象。因此,来自 combineLatest 的管道中的代码根本没有执行,无论新值被发送到您的操作流多少次,并且您总是从 [=18= 接收初始 false 值].

一些建议:

  1. A BehaviorSubject 是一个多播可观察对象,您应该始终将其保密以最小化对其调用 next() 的范围。使用 .asObservable() 方法将其公开为可观察对象,如果任何外部代码需要能够发出新值,请提供 public 方法来执行此操作。您已经在以这种方式处理 baySelectedSubject。考虑对 invalidBay.

    做同样的事情
  2. 切勿将您的订阅代码放在会执行多次的方法中。每次执行该方法时,您最终都会创建一个新订阅。可观察对象将为每个订阅发出值。因此,从 onSubmit() 中删除您的订阅并将其放入 ngOnInit().

  3. 如果您不需要它,请避免存储 Subscription 引用。您可以简单地订阅为 -

this.bayService.invalidBay$.subscribe(value => ...

而不是-

this.subscription = this.bayService.invalidBay.subscribe(value => ...

万一你需要一个Subscription引用,那么记得在ngOnDestroy方法中做清理-

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

一旦您的组件被销毁,这将取消订阅 observable。否则,即使在您的组件被销毁后,Subscription 引用仍会保留可观察对象,这最终会导致内存泄漏。

基于建议的(相对)更好的实现:

服务-

export class BayServiceService {
    private baysUrl = 'api/bays';

    bays$ = this.http.get<Bay[]>(this.baysUrl)
        .pipe(
            tap(data => console.log('Bays: ', JSON.stringify(data))),
            catchError(this.handleError)
        );

    private baySelectedSubject = new BehaviorSubject<number>(0);
    baySelectedAction$ = this.baySelectedSubject.asObservable();

    private invalidBay = new BehaviorSubject<boolean>(false);
    invalidBay$ = this.invalidBay.asObservable();

    selectedBay$ = combineLatest([this.bays$, this.baySelectedAction$])
        .pipe(
            map(([bays, selectedBayNumber]) => {
                let bay = bays.find(p => p.bayCode === selectedBayNumber);
                if (!bay) {
                    this.invalidBay.next(false);
                } else {
                    this.invalidBay.next(true);
                    return bay;
                }
            }));

    selectedBayChanged(selectedBayNumber: number): void {
        this.baySelectedSubject.next(selectedBayNumber);
    }
}

在你的组件中 -

ngOnInit(): void {
    this.bayService.selectedBay$.subscribe(
        p => {
            // do something with the Bay value
        }
    );

    this.bayService.invalidBay$.subscribe(
        p => {
            // do something with the invalidBay value
        }
    );
}

onSubmit(): void {
    this.bayService.selectedBayChanged(this.bayForm.get('bayStart').value);
}

ngOnDestroy(): void {
    // if you stored Subscription reference
    this.subscription.unsubscribe();
}