angularアプリケーションには、コンポーネント/ディレクティブ用のngOnDestroy()
ライフサイクルフックがあり、このフックを使用してオブザーバブルのサブスクライブを解除します。
@injectable()
サービスで作成されたobservableをクリア/破壊したい。 ngOnDestroy()
はサービスでも使用できると言っている投稿を見ました。
しかし、それは良い習慣であり、そうする唯一の方法であり、いつ呼び出されますか?誰か明確にしてください。
OnDestroy ライフサイクルフックはプロバイダーで使用できます。ドキュメントによると:
ディレクティブ、パイプ、またはサービスが破棄されたときに呼び出されるライフサイクルフック。
例 です:
@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)
}
}
上記のコードでは、Service
はFoo
コンポーネントに属するインスタンスであるため、Foo
が破棄されると破棄されることに注意してください。
ルートインジェクターに属するプロバイダーの場合、これはアプリケーションの破棄時に発生します。これは、複数のブートストラップ、つまりテストでのメモリリークを回避するのに役立ちます。
親インジェクターからのプロバイダーが子コンポーネントでサブスクライブされると、コンポーネントの破棄で破棄されません。これは、コンポーネントngOnDestroy
でサブスクライブを解除するコンポーネントの責任です(別の答えで説明します)。
サービスに変数を作成します
subscriptions: Subscriptions[]=[];
各サブスクライブを配列にプッシュします
this.subscriptions.Push(...)
dispose()
メソッドを書く
dispose(){
this.subscriptions.forEach(subscription =>subscription.unsubscribe())
NgOnDestroy中にコンポーネントからこのメソッドを呼び出します
ngOnDestroy(){
this.service.dispose();
}
この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いつ「購読」から購読を解除すべきですか
明確にするために-Observables
を破棄する必要はありませんが、サブスクリプションのみを破棄する必要があります。
他の人が、あなたがサービスでngOnDestroy
を使用できるようになったと指摘しているようです。リンク: https://angular.io/api/core/OnDestroy
アプリケーションを可能な限りモジュール化するために、プロバイダートークンを使用してコンポーネントにサービスを提供することがよくあります。これらはngOnDestroy
というメソッドを取得していないようです:-(
例えば。
export const PAYMENTPANEL_SERVICE = new InjectionToken<PaymentPanelService>('PAYMENTPANEL_SERVICE');
コンポーネントにプロバイダーセクションがある場合:
{
provide: PAYMENTPANEL_SERVICE,
useExisting: ShopPaymentPanelService
}
私のShopPaymentPanelService
には、コンポーネントが破棄されるときにngOnDestroy
メソッドが呼び出されません。私はこれを難しい方法で見つけました!
回避策は、useExisting
とともにサービスを提供することです。
[
ShopPaymentPanelService,
{
provide: PAYMENTPANEL_SERVICE,
useExisting: ShopPaymentPanelService
}
]
これを行ったとき、ngOnDispose
が期待どおりに呼び出されました。
これがバグかどうかはわかりませんが、非常に予想外です。