Angular 2 从组件或服务订阅? [英] Angular 2 subscribe from component or service?

查看:23
本文介绍了Angular 2 从组件或服务订阅?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

上下文

我有一个组件 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆