2017-06-03 29 views
3

我调用函数* ngFor声明HTTP调用使用功能:无限循环,同时在* 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[]); 
    } 

} 

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

回答

4

这不是一个无限循环。每次Angular运行更改检测器以检查是否有任何绑定发生了更改,它需要运行使HTTP调用的方法loadAll()。这是因为它不能确定它最后一次检查没有改变它。你显然不想要这个。需要检查更改的频率可能很可能取决于其他组件(例如,它的父项)。

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

如果你不想使用其他状态变量,你可以作出这样的重放缓存的数据可观察到的链:

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,