webentwicklung-frage-antwort-db.com.de

Angular 4+ ngOnDestroy () im Einsatz - zerstöre beobachtbar

In einer Winkelanwendung haben wir ngOnDestroy() Lifecycle Hook für eine Komponente/Direktive, und wir verwenden diesen Hook, um die Observables abzubestellen.

Ich möchte/beobachtbare Beobachtungen löschen, die in einem @injectable()-Dienst erstellt wurden ..__ Ich habe einige Beiträge gesehen, die besagen, dass ngOnDestroy() auch in einem Dienst verwendet werden kann.

Aber ist es eine gute Praxis und nur eine Möglichkeit, dies zu tun? Wann wird es gerufen? Jemand bitte klären.

34
mperle

OnDestroy Lifecycle-Hook ist in Anbietern verfügbar.

Lebenszyklus-Hook, der aufgerufen wird, wenn eine Anweisung, eine Pipe oder ein Dienst zerstört wird.

Hier ist ein Beispiel :

@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)
  }
}

Beachten Sie, dass Service im obigen Code eine Instanz ist, die zur Foo-Komponente gehört. Sie kann also zerstört werden, wenn Foo zerstört wird.

Für Anbieter, die zum Root-Injektor gehören, geschieht dies bei der Zerstörung der Anwendung. Dies ist hilfreich, um Speicherverluste bei mehreren Bootstraps zu vermeiden, d. H. Bei Tests.

Wenn ein Anbieter von einem übergeordneten Injektor in einer untergeordneten Komponente abonniert wird, wird er bei der Zerstörung der Komponente nicht zerstört. Dies liegt in der Verantwortung der Komponente, sich in der Komponente ngOnDestroy abzumelden (wie in einer anderen Antwort erläutert).

42
estus

Erstellen Sie eine Variable in Ihrem Dienst

subscriptions: Subscriptions[]=[];

Drücken Sie jedes Ihrer Abonnements als

this.subscriptions.Push(...)

Schreiben Sie eine dispose()-Methode

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

Rufen Sie diese Methode von ngOnDestroy aus Ihrer Komponente auf

ngOnDestroy(){
   this.service.dispose();
 }
15
Aravind

Nur um zu klären - Sie brauchen nicht Observables zu zerstören, sondern nur die Abonnements, die sie gemacht haben.

Es scheint, als hätten andere darauf hingewiesen, dass Sie ngOnDestroy jetzt auch mit Services verwenden können. Link: https://angular.io/api/core/OnDestroy

5
apeshev

Vorsicht bei der Verwendung von Token

Um meine Anwendung so modular wie möglich zu gestalten, verwende ich häufig Provider-Token, um einer Komponente einen Dienst bereitzustellen. Es scheint, dass diese NICHT ihre ngOnDestroy -Methoden erhalten, die aufgerufen werden :-(

z.B.

export const PAYMENTPANEL_SERVICE = new InjectionToken<PaymentPanelService>('PAYMENTPANEL_SERVICE');

Mit einem Provider-Abschnitt in einer Komponente:

 {
     provide: PAYMENTPANEL_SERVICE,
     useExisting: ShopPaymentPanelService
 }

Bei meiner ShopPaymentPanelService wird die ngOnDestroy -Methode NICHT aufgerufen, wenn die Komponente entsorgt wird. Ich habe das gerade auf die harte Tour herausgefunden!

Eine Problemumgehung besteht darin, den Dienst in Verbindung mit useExisting bereitzustellen.

[
   ShopPaymentPanelService,

   {
       provide: PAYMENTPANEL_SERVICE,
       useExisting: ShopPaymentPanelService
   }
]

Als ich dies tat, wurde das ngOnDispose wie erwartet aufgerufen.

Nicht sicher, ob dies ein Fehler ist oder nicht, aber sehr unerwartet.

0
Simon_Weaver

Ich bevorzuge dieses takeUntil(onDestroy$)-Muster, das von Pipe-Operatoren aktiviert wird. Ich finde es gut, dass dieses Muster prägnanter und sauberer ist und klar die Absicht vermittelt, ein Abonnement bei Ausführung des OnDestroy Lebenszyklus-Hooks zu beenden.

Dieses Muster funktioniert sowohl für Dienste als auch für Komponenten, die injizierte Observables abonnieren. Der unten stehende Skeleton-Code sollte genügend Details enthalten, um das Muster in Ihren eigenen Service zu integrieren. Stellen Sie sich vor, Sie importieren einen Dienst namens 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();
  }

Das Thema Wann/Wie kann ich den Newsletter abbestellen, wird hier ausführlich behandelt: Angular/RxJs Wann sollte ich das Abo abbestellen

0