上下文
我有一个组件 HospitalComponent
试图显示医院列表。它使用 HospitalService
中的 readAll
方法(从 firebase 返回一个 Observable):
ngOnInit() {
this.hospitalService
.readAll() // Make a firebase call
.subscribe(hospitals => this.hospitals = hospitals);
}
路由 /hospital
插入到此组件 HospitalComponent
。每次我到达 /hospital
时,Angular 2 都会创建一个新的 HospitalComponent
,并对 hospitalService
进行新的调用。
问题
每次我到达 /hospital
时,医院列表都会延迟显示。
问题
从服务构造函数本身检索医院列表是一种好的做法吗?这样,我就可以从后台管理刷新列表,而不会有一些延迟。我会在组件中:
ngOnInit() {
this.hospitals = this.hospitalService.readAll();
}
在服务中:
constructor(private hospitalService: HospitalService) {
hospitalService.subscribe(hospitals => this.hospitals = hospitals);
}
但这意味着要手动管理所有医院变更..
最佳答案
从技术 Angular 来看,这两种“解决方案”几乎相同 - 因为它们基本上做同样的事情,所以如果您只想考虑您的两种解决方案,则取决于您的个人喜好。
但总的来说:尽量避免手动订阅。
有几件事您可以改进(以下代码基于假设,您宁愿显示一个过时的列表,在后台更新而不是显示加载指示器):
- 尽量避免手动订阅(尤其是(!!)在组件中)-> 使用
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
}
}
您的组件(=> 只需注入(inject)服务)
constructor(private hospitalService: HospitalService) {
// nothing to do here
}
组件的模板(=> async-pipe 自动管理订阅和自动取消订阅,所以你不必担心内存泄漏等......)
<div *ngFor="let hospital of (hospitalService.allHospitals$ | async)">
{{hospital.name}}
</div>
第四种(但更广泛)解决方案是使用中央存储,如 ngrx - 因此,对于 ngrx,allHospitals$
的部分基本上将被移动到一个集中管理的存储模块中,您将严格划分您的应用程序,这样一个服务将除了获取和处理之外什么都不做 数据,商店将除了存储和发送数据外什么都不做,而组件将除了显示数据外什么都不做。
关于Angular 2 从组件或服务订阅?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41021487/