在 Angular 中使用带有 RxJS 的声明式/反应式数据访问方法时如何“传递”数据?

Deb*_*ahK 5 rxjs typescript angular

Angular 中数据访问的经典模式建议如下代码:

经典数据访问模式

getProducts(): Observable<Product[]> {
  return this.http.get<Product[]>(this.productsUrl)
    .pipe(
      tap(data => console.log(JSON.stringify(data))),
      catchError(this.handleError)
    );
Run Code Online (Sandbox Code Playgroud)

上面我们有一个方法返回一个 Observable。当数据从 http 端点返回时,该 Observable 以Product[]通用参数定义的形状发出数据,其中Product是一个接口。

对于更具反应性的应用程序,通常建议使用声明性/反应性方法。它将上述方法更改为如下属性声明:

反应式数据访问模式

products$ = this.http.get<Product[]>(this.url)
  .pipe(
    tap(data => console.log(JSON.stringify(data))),
    catchError(this.handleError)
  );
Run Code Online (Sandbox Code Playgroud)

请注意,这在服务中为 Observable 声明了一个属性,而不是一个方法。的$上后缀products$是用于区分是观测量VS其它类型的数据结构,如一般的物体或阵列性质的约定。

当存在 UI 交互性(例如基于选择的过滤)、处理复杂数据(例如组合来自多个端点的数据)以及跨组件共享数据(例如每个组件需要做出反应时)时,通常会使用此模式当数据发生变化时)。

反应式数据访问模式存在一个常见问题。使用这种技术时,我们如何“传递”URL 所需的数据?

例如,假设 http 请求需要一个类别来只下拉该类别的产品:

this.http.get<Product[]>(`${this.url}?cat=${catId}`)
Run Code Online (Sandbox Code Playgroud)

没有方法怎么能把这个类“传入”?

Deb*_*ahK 10

与其考虑如何“传递”数据,不如考虑如何随着时间的推移“发出”该值。为了发出数据,我们使用Subject或定义我们自己的 Observable BehaviorSubject

private categorySubject = new Subject<number>();
categorySelectedAction$ = this.categorySubject.asObservable();

products$ = this.categorySelectedAction$.pipe(
 switchMap(catId=>this.http.get<Product[]>(`${this.url}?cat=${catId}`))
    .pipe(
      tap(data => console.log(data)),
      catchError(this.handleError)
  ));

selectedCategoryChanged(categoryId: number): void {
  this.categorySubject.next(categoryId);
}
Run Code Online (Sandbox Code Playgroud)

在上面的代码中,我们使用Subject. 我们将 Subject 声明为私有,因此无法从我们的服务外部访问它。然后我们使用 公开该主题的只读部分asObservable()

每当用户选择不同的类别时,组件就会调用selectedCategoryChanged它,将选定的 categoryId 发送到我们的主题定义的流中。

对于products$,当发出一个值时,它会通过一组运算符进行管道传输。TheswitchMap是一个高阶映射运算符,它自动订阅内部 Observable (the this.http.get...) 并将结果展平。然后将指定类别的返回产品发送到products$流中。

要查看更完整的解决方案,请参阅此 github:https : //github.com/DeborahK/Angular-RxJS/tree/master/APM-Final

  • 嗨@dmitry-grinko - 对于简单的情况,你是对的。该帖子说“对于更具反应性的应用程序”,意味着应用程序需要更多的组件交互。当我回到办公桌前时,我会添加更多相关细节。谢谢! (2认同)
  • 是的@KamranKhatti NgRx 商店将是一个有效的选择。但这需要购买并学习 NgRx 库。另外,很难将它用于小代码片段。:-) 我这里有一个 NgRx 示例:https://github.com/DeborahK/Angular-NgRx-GettingStarted/tree/master/APM-Demo4 (2认同)