Angular 2 从组件或服务订阅?
Angular 2 subscribe from component or service?
上下文
我有一个组件 HospitalComponent
试图显示医院列表。它使用 HospitalService
中的 readAll
方法(即 returns 来自 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);
}
但这意味着要手动管理所有医院变更..
从技术角度来看,两者 "solutions" 几乎相同 - 因为它们基本上做同样的事情,所以如果您只想考虑您的两个解决方案,则取决于您的个人喜好。
但总的来说:尽量完全避免手动订阅。
有几件事您可以改进(以下代码基于假设,您宁愿显示一个过时的列表,在后台更新而不是显示加载指示器):
- 尽量避免手动订阅(尤其是(!!)在组件中)-> 使用
async
-管道代替
- 尽量避免有状态的组件(如果可能,甚至是服务)-> 改用流
您的服务
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
}
}
您的组件(=> 只需注入服务)
constructor(private hospitalService: HospitalService) {
// nothing to do here
}
组件的模板(=> async-pipe 自动管理订阅和自动退订,所以你不必担心内存泄漏等...)
<div *ngFor="let hospital of (hospitalService.allHospitals$ | async)">
{{hospital.name}}
</div>
第四个(但更广泛的)解决方案是使用像 ngrx 这样的中央存储 - 所以对于 ngrx 基本上 allHospitals$
的一部分将被移动到一个集中管理的存储模块并且您将严格划分您的应用程序,以便服务 除了获取和处理 数据外什么都不做,商店除了存储和发送 什么都不做 ] 数据和组件将 除了显示 数据外什么都不做。
上下文
我有一个组件 HospitalComponent
试图显示医院列表。它使用 HospitalService
中的 readAll
方法(即 returns 来自 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);
}
但这意味着要手动管理所有医院变更..
从技术角度来看,两者 "solutions" 几乎相同 - 因为它们基本上做同样的事情,所以如果您只想考虑您的两个解决方案,则取决于您的个人喜好。
但总的来说:尽量完全避免手动订阅。
有几件事您可以改进(以下代码基于假设,您宁愿显示一个过时的列表,在后台更新而不是显示加载指示器):
- 尽量避免手动订阅(尤其是(!!)在组件中)-> 使用
async
-管道代替 - 尽量避免有状态的组件(如果可能,甚至是服务)-> 改用流
您的服务
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
}
}
您的组件(=> 只需注入服务)
constructor(private hospitalService: HospitalService) {
// nothing to do here
}
组件的模板(=> async-pipe 自动管理订阅和自动退订,所以你不必担心内存泄漏等...)
<div *ngFor="let hospital of (hospitalService.allHospitals$ | async)">
{{hospital.name}}
</div>
第四个(但更广泛的)解决方案是使用像 ngrx 这样的中央存储 - 所以对于 ngrx 基本上 allHospitals$
的一部分将被移动到一个集中管理的存储模块并且您将严格划分您的应用程序,以便服务 除了获取和处理 数据外什么都不做,商店除了存储和发送 什么都不做 ] 数据和组件将 除了显示 数据外什么都不做。