Angulaire 4+ ngOnDestroy() dans le service de détruire observables

dans une application angulaire, nous avons le crochet de cycle de vie ngOnDestroy() pour un composant / directive et nous utilisons ce crochet pour désabonner les observables.

je veux effacer / détruire observable qui sont créés dans un service @injectable() . J'ai vu quelques posts disant que ngOnDestroy() peut être utilisé dans un service.

Mais, est-ce une bonne pratique et la seule façon de le faire et Quand doit-il être appelé ? que quelqu'un clarifie.

26
demandé sur mperle 2017-08-26 22:27:58

4 réponses

OnDestroy lifecycle hook est disponible chez les fournisseurs. Selon les documents:

crochet du cycle de vie qui s'appelle lorsqu'une directive, un tuyau ou un service est détruit.

voici un exemple :

@Injectable()
class Service implements OnDestroy {
  ngOnDestroy() {
    console.log('Service destroy')
  }
}

@Component({
  selector: 'foo',
  template: `foo`,
  providers: [Service]
})
export class Foo {
  constructor(service: Service) {}

  ngOnDestroy() {
    console.log('foo destroy')
  }
}

@Component({
  selector: 'my-app',
  template: `<foo *ngIf="isFoo"></foo>`,
})
export class App {
  isFoo = true;

  constructor() {
    setTimeout(() => {
        this.isFoo = false;
    }, 1000)
  }
}

notez que dans le code ci-dessus Service est une instance qui appartient au composant Foo , donc il peut être détruit quand Foo est détruit.

pour les fournisseurs qui appartiennent à root injector cela se produira sur application destroy, ceci est utile pour éviter les fuites de mémoire avec plusieurs bootstraps, c.-à-d. dans les tests.

Lorsqu'un fournisseur de services de parent injecteur est abonné à la composante enfant, il ne sera pas détruit sur la composante détruire, c'est la responsabilité de la composante de se désabonner dans la composante ngOnDestroy (comme une autre réponse explique).

30
répondu estus 2017-11-23 11:27:10

créer une variable à votre service

subscriptions: Subscriptions[]=[];

poussez chacun de votre abonnement au tableau comme

this.subscriptions.push(...)

Écrire un dispose() méthode

dispose(){
this.subscriptions.forEach(subscription =>subscription.unsubscribe())

appelez cette méthode de votre composant pendant ngOnDestroy

ngOnDestroy(){
   this.service.dispose();
 }
12
répondu Aravind 2017-08-26 19:56:47

Juste pour clarifier - vous n'avez pas besoin de détruire Observables mais seuls les abonnements.

il semble comme d'autres ont souligné que vous êtes maintenant en mesure d'utiliser ngOnDestroy avec les services ainsi. Lien: https://angular.io/api/core/OnDestroy

5
répondu apeshev 2017-08-26 21:56:01

je préfère Ce modèle takeUntil(onDestroy$) activé par des opérateurs pipables. J'aime que ce modèle soit plus concis, plus propre, et qu'il exprime clairement l'intention de tuer un abonnement lors de l'exécution du crochet de cycle de vie OnDestroy .

Ce modèle fonctionne aussi bien pour les services que pour les composants souscrivant à des observables injectés. Le code squelette ci-dessous devrait vous donner assez de détails pour intégrer le modèle dans votre propre service. Imaginez que vous importez un service appelé InjectedService ...

import { InjectedService } from 'where/it/lives';
import { Injectable, OnDestroy } from '@angular/core';
import { Observable } from 'rxjs/Rx';
import { takeUntil } from 'rxjs/operators';
import { Subject } from 'rxjs/Subject';

@Injectable()
export class MyService implements OnDestroy {

  private onDestroy$ = new Subject<boolean>();

  constructor(
    private injectedService: InjectedService
  ) {
    // Subscribe to service, and automatically unsubscribe upon `ngOnDestroy`
    this.injectedService.observableThing().pipe(
      takeUntil(this.onDestroy$)
    ).subscribe(latestTask => {
      if (latestTask) {
        this.initializeDraftAllocations();
      }
    });
  }

  ngOnDestroy() {
    this.onDestroy$.next(true);
    this.onDestroy$.complete();
  }

le sujet de quand/comment se désabonner est traité en détail ici: Angular/RxJS Quand dois-je me désabonner de `Abonnement '

0
répondu Matthew Marichiba 2018-09-08 05:54:43