Angular 2订阅组件或服务?

soy*_*wod 7 observable rxjs firebase angularfire2 angular

上下文

我有一个HospitalComponent试图显示医院列表的组件.它使用的readAll方法HospitalService(从firebase返回一个Observable):

ngOnInit() {
  this.hospitalService
    .readAll() // Make a firebase call
    .subscribe(hospitals => this.hospitals = hospitals);
}
Run Code Online (Sandbox Code Playgroud)

路由/hospital已插入此组件HospitalComponent.每次我到达时/hospital,Angular 2都会创建一个新的HospitalComponent,并且新的呼叫将被发送给hospitalService.

问题

每次到达时/hospital,医院名单都会延迟显示.

从服务构造函数本身检索医院列表是一种好习惯吗?这样,我可以从后台管理刷新列表,而不是有一些延迟.我会在组件中:

ngOnInit() {
  this.hospitals = this.hospitalService.readAll();
}
Run Code Online (Sandbox Code Playgroud)

并在服务中:

constructor(private hospitalService: HospitalService) {
  hospitalService.subscribe(hospitals => this.hospitals = hospitals);
}
Run Code Online (Sandbox Code Playgroud)

但这意味着要手动管理所有医院的变化.

ols*_*lsn 9

从技术角度来看,两种"解决方案"几乎是相同的 - 因为它们基本上做同样的事情,如果你只想考虑你的两个解决方案,那就取决于你的个人品味.

但总的来说:尽量避免手动订阅.

有几件事你可以改进(以下代码基于这样的假设,你宁愿显示一个过时的列表,在后台更新,而不是显示加载指示器):

  • 尽量避免手动订阅(尤其是组件中的(!!)) - >使用async-pipe代替
  • 尽量避免使用有状态组件(如果可能的话,甚至是服务) - >使用流来代替

你的服务

export class HospitalService {
    allHospitals$: BehaviorSubject<IHospital[]> = new BehaviorSubject<IHospital[]>([]);

    // the fetchAll() method can be called in the constructor, or somewhere else in the application e.g. during startup, this depends on your application-flow, maybe some login is required ect...
    fetchAll(): Observable<IHospital[]> {
        const fetch$: Observable<IHospital[]> = ...get_stuff_from_firebase().share();
        fetch$
            .do(allHospitals => this.allHospitals$.next(allHospitals);
            .subscribe();
        return fetch$; // optional, just in case you'd want to do something with the immediate result(or error) outside the service
    }
}
Run Code Online (Sandbox Code Playgroud)

你的组件(=>只是注入服务)

constructor(private hospitalService: HospitalService) {
    // nothing to do here
}
Run Code Online (Sandbox Code Playgroud)

组件的模板(=> async-pipe自动管理订阅并自动取消订阅,因此您不必担心内存泄漏等...)

<div *ngFor="let hospital of (hospitalService.allHospitals$ | async)">
    {{hospital.name}}
</div>
Run Code Online (Sandbox Code Playgroud)

第四个(但更加扩展的)解决方案是使用像ngrx这样的中央存储- 所以使用ngrx基本上将部分allHospitals$移动到集中管理的商店模块,您将严格划分您的应用程序,以便服务将做什么,但取和处理数据,商店将做什么,但存储和发射数据,并且组件将做什么,但显示数据.