angular - 在带有异步管道的 *ngFor 中使用带有 http-call 的函数时无限循环

标签 angular typescript asynchronous rxjs

我在 *ngFor 语句中调用函数:

@Component({
  selector: 'foo-view',
  template: '<div *ngFor="let foo of loadAll() | async"></div>'
})
export class FooComponent {

  loadAll() : Observable<Foo[]> {
    return this.http.get(`api/foos`)
      .map(response => response.json() as Foo[]);
  }

}

当代码开始时,它会在无限循环中一遍又一遍地发送 http 请求。

为什么? 我该怎么做才能避免这种情况?

附言我知道像

这样的标准解决方法
@Component({
  selector: 'foo-view',
  template: '<div *ngFor="let foo of foos"></div>'
})
export class FooComponent implements OnInit {

  foos: Foo[] = [];

  ngOnInit() {
    loadAll().subscribe(foos => this.foos = foos);
  }

  loadAll() : Observable<Foo[]> {
    return this.http.get(`api/foos`)
      .map(response => response.json() as Foo[]);
  }

}

但我正在寻找删除多余变量的方法。

最佳答案

这不是无限循环。每次 Angular 运行变化检测器来检查是否有任何绑定(bind)发生变化时,它需要运行 loadAll() 方法来进行 HTTP 调用。这是因为它不能确定它在上次检查时没有改变。你显然不想要这个。它需要多久检查一次更改很可能也取决于其他组件(例如它的父组件)。

避免这种情况的一种方法正是您通过创建属性 foos: Foo[] 展示的方法。

如果你不想使用另一个状态变量,你可以创建一个重放缓存数据的 Observable 链:

private cached;

ngOnInit() { 
  this.cached = this.http.get(`api/foos`)
    .map(response => response.json() as Foo[])
    .publishReplay(1)
    .refCount()
    .take(1);
}

然后在您的模板中您可以只使用:

<div *ngFor="let foo of cached | async"></div>

现在它会在开始时只发出一个请求,每次有人订阅时它都会重放值并完成。

此外,从 RxJS 5.4.0 开始,您可以使用 shareReplay(1) 而不是 .publishReplay(1).refCount()

顺便说一句,您还可以使用 changeDetection 属性更改组件上的变更检测策略,以手动运行变更检测。参见 ChangeDetectionStrategy ,

关于angular - 在带有异步管道的 *ngFor 中使用带有 http-call 的函数时无限循环,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44345508/

相关文章:

angular - 某些事件未触发更改检测

javascript - 我的 Angular 2 对象打印在控制台上,但单个属性没有从模板打印

angular - 调用受B2C保护的Function App API的Angular应用接收500,Function接收404

javascript - 如何从异步调用返回响应?

javascript - 使用 sequelize 获取下一条记录

C 非阻塞键盘输入

javascript - angular 5 - 模态指令

reactjs - 错误 TS2430 : Interface 'RcFile' incorrectly extends interface 'File' in antd

javascript - 无法发送 PDF(*.pdf) 扩展名的文件

javascript - 在节点模块中导入 Typescript 和 Js 文件时出现问题