【问题标题】:Infinite loop while use function with http-call in *ngFor with async pipe无限循环同时使用带有异步管道的 *ngFor 中的 http-call 函数
【发布时间】:2017-11-04 20:14:59
【问题描述】:

我在 *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 typescript asynchronous rxjs


    【解决方案1】:

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

    避免这种情况的一种方法正是您通过创建属性 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

    【讨论】:

      猜你喜欢
      • 2019-10-04
      • 1970-01-01
      • 2018-02-03
      • 2017-05-07
      • 2018-07-26
      • 1970-01-01
      • 2021-09-28
      • 2019-04-11
      • 2016-03-29
      相关资源
      最近更新 更多