首页 > 解决方案 > 使用 Observables 组合视图模型

问题描述

下面的代码简单地说明了我试图用 2 个模型做什么。假设我们有一个Book模型和一个Author模型。首先,我们获取Books使用返回类型的服务的列表Observable<Book>。然后我们使用*ngFor遍历每一个,但我们还想Author在书的旁边显示,所以在我们的迭代中,我们有一些像这样的 HTML:

<span>{{ getAuthorName(book) | async }}</span>

getAuthorName有自己的请求AuthorService就去取作者ID。问题是,当我们在Observable<string>这里返回时,浏览器完全崩溃,因为更改检测运行异常,因为每个摘要周期都返回一个“新”可观察对象,这导致更改检测再次无休止地运行,对吗?

下面的代码可以很容易地放入 StackBlitz 并复制(我没有链接到它,因为它会炸毁你的浏览器 CPU)

<ul>
  <li *ngFor="let item of getData() | async">
    {{ getOtherData(item.id) | async }}
  </li>
</ul>
import { Component } from '@angular/core';
import { of } from 'rxjs';
import { filter, map } from 'rxjs/operators';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
  name = 'Angular';

  getData() {
    return of([{
      id: 1
    },{
      id: 2
    },{
      id: 3
    }]);
  }

  getOtherData(id: number) {
    const data = of([{
      id: 1,
      name: 'Matt'
    },{
      id: 2,
      name: 'Steve'
    },{
      id: 3,
      name: 'Alice'
    }]);

    return data.pipe(
      map(x => x.find(d => d.id == id))
    )
  }
}

显然有一些优化,比如缓存作者等,可以在这里完成,但总的来说,在 RXJS 的世界中应该如何处理这种情况?我知道有完整的框架来处理像 Akita 和 ngrx 这样的状态,但是如果我不想处理所有这些并且只想用 raw 构建我的应用程序rxjs怎么办?这个问题的预期解决方案是什么?您是否使用其他一些 rxjs 运算符来阻止这种情况发生?(我找不到任何对此有帮助的东西,因为它Obserable每次都返回一个新的)你必须只使用视图模型而不是方法吗?这样,ei 总是只是对 observable 的一个引用?(例如,在我们将视图迭代到单个可观察对象之前,BookAuthorViewModel哪个属性会被设置?$author

我还没有找到一个“感觉正确”的解决方案,我觉得我被迫使用这些状态管理框架只是为了做这样的简单事情。

标签: angularrxjs

解决方案


你不应该在你的视图中调用方法。如果您有一个返回 observable 的方法,那么每次更改保留检查值时都会创建一个新的 observable。

data$ = of([{
  id: 1
},{
  id: 2
},{
  id: 3
}]);

otherData$ = of([{
  id: 1,
  name: 'Matt'
},{
  id: 2,
  name: 'Steve'
},{
  id: 3,
  name: 'Alice'
}]);

然后绑定到 observable

<li *ngFor="let item of data$ | async">
  {{ otherData$ | async | find: item.id }}
</li>

并制作查找管道

@Pipe({
  name: 'find'
})
export class FindPipe implements PipeTransform {
  transform(options, id): string {
    return options.find(option => option.id === id);
  }
}

StackBlitz https://stackblitz.com/edit/angular-6vgosc


推荐阅读