Angular 2 从组件或服务订阅? [英] Angular 2 subscribe from component or service?
问题描述
上下文
我有一个组件 HospitalComponent
试图显示医院列表.它使用 HospitalService
中的 readAll
方法(从 firebase 返回一个 Observable):
ngOnInit() {this.hospitalService.readAll()//进行 firebase 调用.订阅(医院 => this.hospitals = 医院);}
路由/hospital
被插入到这个组件HospitalComponent
.每次我到达 /hospital
时,Angular 2 都会创建一个新的 HospitalComponent
,并对 hospitalService
进行新的调用.
问题
每次我到达/hospital
,医院列表都会延迟显示.
问题
从服务构造函数本身检索医院列表是一个好习惯吗?这样,我可以从后台管理刷新列表,而不是有一些延迟.我会在组件中:
ngOnInit() {this.hospitals = this.hospitalService.readAll();}
并在服务中:
构造函数(私人医院服务:HospitalService){医院服务.订阅(医院 => this.hospitals = 医院);}
但这意味着手动管理所有医院变更..
从技术角度来看,这两个解决方案"几乎是一样的——因为它们基本上做同样的事情,如果你只是想考虑的话,这取决于你的个人品味您的两个解决方案.
但总的来说:尽量避免手动订阅.
您可以改进一些事情(以下代码基于这样的假设,即您宁愿显示在后台更新的过时列表而不是显示加载指示器):
- 尽量避免手动订阅(尤其是组件中的(!!))-> 使用
async
-pipe 代替 - 尽量避免有状态的组件(如果可能,甚至是服务)-> 改用流
您的服务
导出类 HospitalService {allHospitals$: BehaviorSubject= new BehaviorSubject([]);//fetchAll() 方法可以在构造函数中调用,也可以在应用程序的其他地方调用,例如在启动期间,这取决于您的应用程序流程,也许需要一些登录等...fetchAll(): Observable{const fetch$: Observable= ...get_stuff_from_firebase().share();取$.do(allHospitals => this.allHospitals$.next(allHospitals);.订阅();返回取值$;//可选,以防万一您想对服务外的即时结果(或错误)进行处理}}
您的组件(=> 只需注入服务)
构造函数(私人医院服务:HospitalService){//无所事事}
组件的模板(=> async-pipe 自动管理订阅并自动取消订阅,因此您不必担心内存泄漏等...)
{{医院名称}}
<小时>
第四个(但更多扩展)解决方案是使用像 ngrx 这样的中央存储 - 所以使用 ngrx 基本上 allHospitals$
的部分将被移动到一个集中管理的存储模块,你将严格划分你的应用程序,这样一个服务将除了获取和处理之外什么都不做em> 数据,存储将除了存储和发送数据之外什么都不做,而一个组件将除了显示数据之外什么都不做.
Context
I have a component HospitalComponent
that tries to show a list of hospitals. It uses the readAll
method from the HospitalService
(that returns an Observable from firebase) :
ngOnInit() {
this.hospitalService
.readAll() // Make a firebase call
.subscribe(hospitals => this.hospitals = hospitals);
}
The route /hospital
is plugged to this component HospitalComponent
. Each time I reach /hospital
, Angular 2 make a new HospitalComponent
, and a new call is made to the hospitalService
.
Problem
Each time I reach /hospital
, the hospital list is showing with delay.
Question
Is it a good practice to retrieve the hospital list from the service constructor itself ? This way, I can manage the refresh list from background, instead of having some delay. I would have in the component :
ngOnInit() {
this.hospitals = this.hospitalService.readAll();
}
and in the service :
constructor(private hospitalService: HospitalService) {
hospitalService.subscribe(hospitals => this.hospitals = hospitals);
}
But this implies to manage manually all hospital changes ..
From a technical viewpoint both "solutions" are pretty much equal - since they basically do the same thing it is up to your personal taste if you just want to conside your two solutions.
But in general: Try to avoid manual subscriptions at all.
There are a couple things that you can improve (the following code is based on the assumption, that you'd rather show an outdated list, that is updated in the background than to show a loading-indicator):
- try to avoid manual subscriptions (especially(!!) in components) -> use the
async
-pipe instead - try to avoid stateful components (even services if possible) -> use streams instead
Your Service
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
}
}
Your component (=> just inject the service)
constructor(private hospitalService: HospitalService) {
// nothing to do here
}
The template of the component (=> the async-pipe automatically manages the subscription and unsubscribes automatically as well, so you don't have to worry about memory-leaks ect...)
<div *ngFor="let hospital of (hospitalService.allHospitals$ | async)">
{{hospital.name}}
</div>
A fourth(but much more extended) solutions would be to use a central store like ngrx - So with ngrx basically the part of allHospitals$
would be moved to a centrally managed store-module and you would strictly divide up your application, so that a service will do nothing but fetching and processing data, the store will do nothing but storing and emitting data and a component will do nothing but displaying data.
这篇关于Angular 2 从组件或服务订阅?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!