【问题标题】:Understanding RxJS BehaviorSubject理解 RxJS BehaviorSubject
【发布时间】:2021-04-19 09:28:30
【问题描述】:

我们尝试使用 BehaviorSubject 在多个组件之间共享 API 数据。在我的组件上,我正在触发 HTTP 请求并在返回响应后更新主题。

组件.ts

onClick() {
    this.service.getCompanies();
    this.service.companiesList$.subscribe(companies => {
        console.log(companies.length); // 0 and then 1
    });
}

service.ts

companiesList$ = new BehaviorSubject([]);

getCompanies() {
    return this.http.get(myUrl).subscribe((res: any) => {
        this.companiesList$.next(res.data);
    });
}

请求完成后,如何仅访问 BehaviourSubject 中最后发出的值?

【问题讨论】:

  • 正如一些回复所暗示的,您不需要将 HTTP 调用提供的 Observable 包装在另一个 Observable(BehaviorSubject)中。你已经有了一个可以使用的 Observable。考虑尝试对 Observables 使用声明性方法。这将使通知更容易。有关更多信息,请参阅:youtube.com/watch?v=Z76QlSpYcck

标签: angular rxjs observable behaviorsubject


【解决方案1】:

也许您可以尝试以下操作,将 http 请求的 observable 保存在服务中,并在其上应用 shareReplay(1) 运算符。然后在你的组件中你可以像下面这样使用它:

组件.ts

onClick() {
    this.service.getCompanies().subscribe(companies => {
        console.log(companies);
    });
}

service.ts

$companies =  this.http.get(myUrl).pipe(shareReplay(1));

getCompanies() {
    this.companies$;
}

【讨论】:

    【解决方案2】:

    虽然从技术上讲您可以使用companiesList$.getValue(),但我建议您不要使用subscribe() 在您的组件中创建订阅,而是使用AsyncPipe (ref)。它可能看起来像这样:

    组件.ts

    companies$ = this.service.companiesList$.asObservable();
    
    onClick() {
      this.service.getCompanies();
    }
    

    component.html

    <div *ngIf="companies$ | async as companies">
      <!-- your stuff -->
      {{ companies.length }}
    </div>
    

    【讨论】:

    • 我不想在模板上列出公司。我想在收到结果后通过 CompaniesList$ behaviorSubject 访问 API 公司
    • 然后您可以执行this.service.companiesList$.pipe(skip(1)).subscribe(companies =&gt; {console.log(companies.length); }); 之类的操作。 BehaviorSubject 有一个初始值(在这种情况下为[]),如果你skip 它,你应该总是在订阅中拥有最新的值。如果不需要初始值,也可以考虑使用ReplaySubject 甚至Subject
    【解决方案3】:

    要获取最后一个发射值,请使用:

    companiesList$.getValue().

    如果您要在流中使用它,请使用withLatestFrom operator

    【讨论】:

      【解决方案4】:

      我认为这里缺少的答案是您使用的是 BehaviourSubject,这是错误的主题类型。

      简而言之:

      • 主题将仅从您订阅时开始输出值。因此,如果在 Subject 上调用了 5 次 emit,然后一个组件订阅了,他们将不会看到之前的 5 次发射。

      • 当您订阅时,ReplaySubject 将立即输出 X 个值。因此,如果我有一个 ReplaySubject(1),并且我输出了 5 次值,那么组件就会订阅。他们将立即收到最后一个 1 值,然后他们将继续收到更多的发射。

      • BehaviourSubject 几乎与 ReplaySubject 相同,只是它有一个始终会发出的 默认 值,无论您是否对主题调用了 emit。

      在你的代码中你有:

      companiesList$ = new BehaviorSubject([]);
      

      所以即使在你调用 emit 之前,任何订阅它的人都会立即收到一个空数组。因此,我认为在您问题的字里行间阅读时,您在订阅时遇到了接收空数组的问题,然后您正在接收实际数据。

      您可以使用 ReplaySubject 解决此问题:

      companiesList$ = new ReplaySubject(1);
      

      在第一次发射之前不会输出任何内容,那么任何订阅都将始终收到这个“最后一次”发射。

      值得在这里学习每种主题的区别:https://tutorialsforangular.com/2020/12/12/subject-vs-replaysubject-vs-behaviorsubject/

      【讨论】:

        猜你喜欢
        • 2017-05-04
        • 1970-01-01
        • 2019-10-02
        • 2018-08-31
        • 1970-01-01
        • 2018-11-07
        • 2020-09-27
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多