创建和侦听具有动态负载的 HTTP 可观察对象的正确方法

Proper way to create and listen to a HTTP observable with dynamic payload

场景

用户有一个菜单,该菜单创建了一组汽车标准,用于过滤出服务器端的结果。 当用户点击 Load 按钮时,它会发送条件集以获得正确的结果,然后将它们传递给 child 组件进行显示。

我正在尝试通过创建一个可观察对象来正确地做到这一点,虽然它有效,但它闻起来不对。

Parent HTML

<h3>Select Criteria</h3>
<div>
<!-- Bunch of dropdowns and radio buttons and gizmos that form the filter menu omitted for brevity-->
</div>
<button (click)="loadCars()">Load Cars</button>
<child-comp-table [dataSet]="results$ | async"><child-comp-table>

Parent TS

var _results$ = new BehaviorSubject<any[]>([]);
readonly results$ = this._results$.asObservable();

loadCars() {
    // construct payload based on selected criteria and store in postPayload variable

    this.http.post(url, postPayload).subscribe((res:any) => {
        this._results$.next(res.data);
    });
}

这是设置它的正确方法吗,我的担心源于我必须订阅而不是使用现有管道这一事实。

this.http.post(url, postPayload) returns 一个 Observable,所以我不明白你为什么订阅它并将结果“保存”在行为主题中。

我会按照以下方向进行:

let results$ = of([]); // init the obs with an observable containing empty list

loadCars() {
    this.results$ = this.http.post(url, postPayload);
}

顺便说一下,我也会取出对其自身服务的 HTTP 调用,但那是另一回事

在类似情况下,我倾向于的是以下

  • 有服务class,例如carService,“调用 http”逻辑的地方
  • carService 公开了一个 API 方法,可以调用该方法来触发调用(例如 loadcars(postPayload)
  • carService 还公开了一个 Observable(例如 loadCarsResult$)作为 API,任何想要收到调用结果通知的人都必须订阅 loadCarsResult$

carService的实现和你开发的非常相似,只是抽离成一个单独的服务,像这样

@Injectable({
  providedIn: 'root',
})
export class carService {
  private _results$ = new BehaviorSubject<any[]>([]);
  public results$ = this._results$.asObservable();

  loadCars(postPayload) {
    // pass the _result$ Subject to the subscribe method, which ensures that
    // next, error and complete are correctly invoked
    this.http.post(url, postPayload).subscribe(this._results$);
  }
}

这样你就创建了一个“多播”机制。换句话说,许多组件可以 subscribe 到相同的 result$ Observable,并且所有组件都将在 http 调用的结果到达时立即更新。

看待同一件事的另一种方式是认为您已将 http 调用的调用与返回结果的使用分开。