使用 rxjs ReplaySubject 在两个组件之间共享数据的正确方法是什么?

What is the proper way to share data between two components using rxjs ReplaySubject?

我开发了一个有两个视图的组件。组件 A 有联系表格,组件 B 是 "Thank you" 页面。

组件 A: 您填写表格并提交。 一旦响应到达,就会创建一个新的 ReplaySubject 值。 用户将被路由到组件 B。

组件 B: 组件已初始化。 组件从主题中获取值。 视图已呈现并显示感谢消息。

HTTP调用响应(表单数据post请求成功后返回):

{
   "status": 200,
   "body": {
              "message": "We have received your request with the card information below and it will take 48h to be processed. Thank you!",
              "card": {
                    "name": "John Doe",
                    "email": "john.doe@gmail.com",
                    "accountNumber": "12345-67890"
              }
            },
   "type": "ItemCreated"
}

组件 A(表单)代码:

import { Component } from '@angular/core';
import { FormBuilder, Validators } from '@angular/forms';
import { RequestCardWidgetService } from './request-card-widget.service';
import { RouterService } from '@framework/foundation/core';
import { Item } from '@pt/request-card-data'

@Component({
  selector: 'pt-request-card-form',
  templateUrl: './request-card-form.template.html',
  providers: [RouterService]
})
export class RequestCardFormComponent {
  constructor(private fb: FormBuilder, private data: RequestCardWidgetService, private router: RouterService){}

  item: Item = {
    name: '',
    email: '',
    accountNumber: ''
  };

  requestCardForm = this.fb.group({
    name: ['', Validators.required],
    email: ['', Validators.email],
    accountNumber: ['', Validators.required]
  })

  onSubmit() {
    this.item = this.requestCardForm.value;
    this.data.requestCard(this.item)
      .subscribe(data => {
        this.data.processResult(data);
        this.router.navigate(['/success']);
      });
  }

}

组件 B(感谢页面)代码:

import { Component } from '@angular/core';
import { RequestCardWidgetService } from './request-card-widget.service';

@Component({
  selector: 'pt-request-card-success',
  templateUrl: './request-card-success.template.html'
})
export class RequestCardSuccessComponent {
  messages: any; // TODO: To use the proper type...

  constructor( private requestCardService: RequestCardWidgetService) {
    this.messages = this.requestCardService.message;
  }
}

组件 B 模板(感谢页面):

<div *ngIf='(messages | async) as msg'>
  {{ msg.message}}
</div>

组件服务代码:

import { Injectable } from '@angular/core';
import { HttpResponse } from '@angular/common/http';

import { Observable, ReplaySubject } from 'rxjs';
import { map, take } from 'rxjs/operators';

import {
  RequestCardDataService,
  Item,
  ItemCreated
} from '@example/request-card-data';

@Injectable()
export class RequestCardWidgetService {

  constructor(private dataService: RequestCardDataService) { }

  private readonly results = new ReplaySubject<ItemCreated>();

  readonly message: Observable<ItemCreated> = this.results; // Message Line. This is the variable that I'm rendering in the template. Is this the correct way of extracting subject values?

  requestCard (card: Item): Observable<ItemCreated> {
    return this.dataService.postCardRecord(card).pipe(
      take(1),
      map((response: HttpResponse<ItemCreated>): ItemCreated | {} => {
        return response.body
          ? response.body
          : {};
      })
    );
  }

  processResult(data: ItemCreated) {
    this.results.next(data);
  }

}

回顾: 组件 A 有一个表单。提交表单后,结果将作为新值存储在主题中。用户被路由到感谢页面。 感谢页面组件呈现元素并从主题获取最新值。然后它呈现内容。

此代码有效,但我有一些问题。

问题: 这是使用主题的正确方法吗?

这是:

readonly message: Observable<ItemCreated> = this.results;

从主题中提取值的正确方法? (我将 'message' 传递给视图。)

有没有更好的方法可以达到同样的效果? 提前致谢。

这是使用主题的正确方法吗?

ReplaySubect unconstrained 将重播它之前向新订阅者发出的所有值。这可能会导致用户可能会收到之前发出的消息,直到他们最终收到当前消息。因此,要么限制主题,要么考虑使用 BehaviorSubject

从主题中提取值

A Subject 及其所有导数都是 Observables 和 Observers。向消费者提供主题时,您不想公开 Observer 接口,即消费者永远不能调用 nexterrorcomplete。因此,正如评论中所建议的那样,您应该确保只通过首先调用 asObservable 方法向消费者公开 Observable 接口。

readonly message: Observable<ItemCreated> = this.results.asObservable();

后续步骤

如果您想继续在组件之间使用基于服务的通信,那么我认为您有机会根据问题评论中链接的文档 clean/refine 您的代码。

如果您的应用程序变得越来越复杂,我会引导您使用 Redux 风格的架构并研究 NgRx,特别是使用 effects 来管理副作用。

Effects 可以通过简单、谨慎的可观察结构满足您的所有要求,即处理表单提交、接收响应、甚至导航到成功页面的效果。 More information about effects can be found here.

redux 架构对于简单的任务来说可能有点矫枉过正,但如果你正在开发一个管理大型状态树的大型应用程序,我更喜欢这种方法而不是基于服务的集成。