先日の ng-japan OnAir を視聴していて知ったこと。サービスに ngOnDestroy
が書けるとのこと。知らなかった…!
この記事のコードの前提条件
- Angular 15
サービス
コンポーネントとサービスのライフタイムが一致する場合
コンポーネントメタデータの providers
でサービスを指定する。このようにするとエレメントインジェクターでサービスのインスタンスが生成され、コンポーネントとサービスのライフタイムが一致する。
コンポーネント破棄のタイミングでサービス内の ngOnDestroy
が呼ばれる。
コンポーネントよりサービスのほうが長く生存する場合
コンポーネントメタデータの providers
でサービスを指定しない。このようにするとルートインジェクターでサービスのインスタンスが生成され、コンポーネントよりサービスほうが長く生存する。(モジュールインジェクターを使っても同じ)
コンポーネント破棄のタイミングでサービス内の ngOnDestroy
は呼ばれない。
検証してみる
ルーティングを宣言して、ページ移動によりコンポーネントが生成・破棄されるようにした。
サービスの ngOnDestroy
が呼ばれたかコンソール出力で判定する。
home → foo → home
とリンクを辿る。 FooComponent(エレメントでサービス注入)が破棄されるタイミングでサービスの ngOnDestroy
が呼ばれる。
home → bar → home
とリンクを辿る。BarComponent(ルートでサービス注入)が破棄されるタイミングでサービスはまだ生存しているため ngOnDestroy
は呼ばれない。
検証したコードは以下のURLで公開。
https://codesandbox.io/s/happy-heisenberg-n6018
ユースケース
サービス内で Observable を購読したり、setInterval で定期処理を実行しているようなケースで役立つ。
コンポーネントの ngOnDestroy
で呼び出していた終了処理がサービスの「自分自身が破棄されたタイミング」という関心事になり、終了処理の呼び忘れなどが防げる。利用者であるコンポーネントはインジェクターを変えることで終了処理のタイミングを指示できるようになる。