Angular 4+ ngOnDestroy()サービス中-オブザーバブルを破棄


103

角度のあるアプリケーションではngOnDestroy()、コンポーネント/ディレクティブのライフサイクルフックがあり、このフックを使用してオブザーバブルをサブスクライブ解除します。

@injectable()サービスで作成されたオブザーバブルをクリア/破壊したい。ngOnDestroy()サービスでも利用できるという投稿をいくつか見ました。

しかし、それは良い習慣であり、それを行う唯一の方法であり、いつ呼び出されるのですか?誰かが明確にしてください。

回答:


119

OnDestroyライフサイクルフックはプロバイダーで使用できます。ドキュメントによると:

ディレクティブ、パイプ、またはサービスが破棄されたときに呼び出されるライフサイクルフック。

次に例を示します。

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

@Component({
  selector: 'foo',
  template: `foo`,
  providers: [Service]
})
export class Foo implements OnDestroy {
  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)
  }
}

上記のコードでServiceは、Fooコンポーネントに属するインスタンスであるため、が破棄されるFooと破棄される可能性があることに注意してください。

ルートインジェクターに属するプロバイダーの場合、これはアプリケーションの破棄時に発生します。これは、複数のブートストラップ、つまりテストでのメモリリークを回避するのに役立ちます。

親インジェクターからのプロバイダーが子コンポーネントでサブスクライブされている場合、それはコンポーネント破棄で破棄されません。これはコンポーネントでサブスクライブ解除するコンポーネントの責任ですngOnDestroy(別の回答で説明されています)。


違うclass Service implements OnDestroy?そして、サービスがモジュールレベルで提供されている場合、これが呼び出されたときにどう思いますか
Shumail

1
implements OnDestroy何も影響しませんが、完全にするために追加できます。のように、モジュールが破壊されたときに呼び出されますappModule.destroy()。これは、複数のアプリの初期化に役立つ場合があります。
Estus Flask 2017

1
サービスを使用するすべてのコンポーネントに登録解除が必要ですか?
Ali Abbaszade

2
Plunkerはので、ここで例のStackBlitzバージョンだ、私のために働いていなかった。stackblitz.com/edit/angular-mggk9b
compuguru

1
これを理解するのに少し苦労しました。しかし、この議論は、私は、ローカルとグローバルサービスの違いを理解する助け:stackoverflow.com/questions/50056446/...あなたは「クリーンアップ」にしたか否かは、あなたのサービスの範囲から依存し、私は思います。
ジャスミン

25

サービスに変数を作成します

subscriptions: Subscriptions[]=[];

各サブスクライブを配列にプッシュします

this.subscriptions.push(...)

dispose()メソッドを書く

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

ngOnDestroy中にコンポーネントからこのメソッドを呼び出します

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

お返事ありがとうございます。このngOnDestroyがいつ呼び出されるかわかりますか??
mperle

はい、それは、ディレクティブまたはコンポーネントが破棄される前に、そのクリーンアップ呼び出しを示しています。しかし、それがサービスにも適用できるかどうかを理解したいだけですか?
mperle

モジュールがアンロードされてもサービスはクリアされません
Aravind

2
ライフサイクルフックは該当しません@injectables
Aravind

@Aravind彼らがいつ紹介されたかはわかりませんが、紹介されています
Estus Flask 2017

11

このtakeUntil(onDestroy$)パターンは、pipableオペレーターによって有効化されることを好みます。このパターンはより簡潔でクリーンであり、実行時にサブスクリプションを強制終了する意図を明確に伝えているのが好きですOnDestroyライフサイクルフックの。

このパターンは、サービスと、注入されたオブザーバブルにサブスクライブするコンポーネントで機能します。以下のスケルトンコードは、パターンを独自のサービスに統合するのに十分な詳細を提供します。というサービスをインポートしているとしましょう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();
  }

いつ、どのように購読を解除するかについてのトピックは、ここで広くカバーされています:Angular / RxJs `Subscription`から購読を解除する必要があるとき


5

明確にするために-破棄する必要はなくObservables、それらに対して行われたサブスクリプションのみを破棄します。

他の人もあなたがngOnDestroyサービスでも使用できるようになったと指摘しているようです。リンク:https : //angular.io/api/core/OnDestroy


1
あなたはそれをより詳しく説明してくださいすることができます
Aravind

2

トークンを使用する場合の注意

アプリケーションを可能な限りモジュール化しようとする場合、プロバイダートークンを使用してコンポーネントにサービスを提供することがよくあります。これらはngOnDestroy呼び出されたメソッドを取得していないようです:-(

例えば。

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

コンポーネントにプロバイダーセクションがある場合:

 {
     provide: PAYMENTPANEL_SERVICE,
     useExisting: ShopPaymentPanelService
 }

ShopPaymentPanelServicengOnDestroy、コンポーネントが破棄されるときに呼び出されるメソッドを持っていません。私はこれを難しい方法で見つけました!

回避策は、と組み合わせてサービスを提供することuseExistingです。

[
   ShopPaymentPanelService,

   {
       provide: PAYMENTPANEL_SERVICE,
       useExisting: ShopPaymentPanelService
   }
]

私がこれをしたとき、それはngOnDispose期待通りに呼ばれました。

これがバグかどうかはわかりませんが、非常に予想外です。


素晴らしいヒント!私の場合、なぜうまくいかないのかと思っていました(具体的な実装のトークンとして抽象クラスインターフェイスを使用していました)。
Andrei Sinitson
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.