我在* 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请求。
为什么呢? 我该怎么做才能避免这种情况?
P.S。我知道标准的解决方法,如
@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[]);
}
}
但我正在寻找减少多余变量的方法。
答案 0 :(得分:4)
这不是一个无限循环。每当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,