简体   繁体   English

Angular 2订阅组件或服务?

[英]Angular 2 subscribe from component or service?

Context 上下文

I have a component HospitalComponent that tries to show a list of hospitals. 我有一个组件HospitalComponent ,试图显示医院列表。 It uses the readAll method from the HospitalService (that returns an Observable from firebase) : 它使用来自HospitalServicereadAll方法(从readAll返回一个Observable):

ngOnInit() {
  this.hospitalService
    .readAll() // Make a firebase call
    .subscribe(hospitals => this.hospitals = hospitals);
}

The route /hospital is plugged to this component HospitalComponent . 路线/hospital插入此组件HospitalComponent Each time I reach /hospital , Angular 2 make a new HospitalComponent , and a new call is made to the hospitalService . 每次我到/hospital ,角2作出新HospitalComponent ,一个新的呼叫到由hospitalService

Problem 问题

Each time I reach /hospital , the hospital list is showing with delay. 每次到达/hospital ,医院名单都会延迟显示。

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 尽量避免手动订阅(尤其是组件中的(!!)) - >使用async -pipe代替
  • 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...) 组件的模板(=> async-pipe自动管理订阅并自动取消订阅,因此您不必担心内存泄漏等...)

<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. 第四个(但更加扩展的)解决方案是使用像ngrx这样的中央商店 - 所以使用ngrx基本上所有医院的部分allHospitals$将被转移到集中管理的商店模块,你会严格划分你的应用程序,这样一来服务除了获取和处理数据之外什么也不做,商店除了存储和发送数据之外什么都不做, 除了显示数据之外,组件什么都不做。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM