Dev Study
← Angular コース

62. DestroyRef と takeUntilDestroyed — 後片付けを宣言的に

ライフサイクルフックのレッスンで、コンポーネントが破棄されるときは ngOnDestroy で購読解除などの後片付けをすると学びました。ただ、解除のためだけに Subscription をプロパティに持ち、ngOnDestroy を実装するのはかなり定型的です。現代のAngularには、この後片付けをもっと短く書ける道具が2つあります。DestroyRef と takeUntilDestroyed です。

DestroyRef は inject(DestroyRef) で受け取れるサービスで、onDestroy(コールバック) と登録しておくと、そのコンポーネントが破棄されるときに自動で実行してくれます。タイマーの解除やライブラリの後始末など「破棄時にやりたいこと」を、発生させたその場で登録できるのが利点です。RxJSの購読には専用の takeUntilDestroyed() があり、pipe(takeUntilDestroyed()) を1行挟むだけで、破棄と同時に購読が自動解除されます。

takeUntilDestroyed() を引数なしで使えるのはコンストラクタなどの注入コンテキストの中だけで、それ以外の場所では takeUntilDestroyed(this.destroyRef) と明示的に渡します。なお、これはあくまで自分で subscribe するときの安全網です。asyncパイプや toSignal で済む場面ではそちらが第一候補、という優先順位はこれまで通りです。

サンプルコード(フレームワーク環境が必要なため表示のみ)

import { Component, inject, DestroyRef } from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { interval } from 'rxjs';

@Component({
  selector: 'app-clock',
  template: '<p>経過: {{ seconds }} 秒</p>',
})
export class ClockComponent {
  private destroyRef = inject(DestroyRef);
  seconds = 0;

  constructor() {
    // 破棄と同時に自動で購読解除される。ngOnDestroy は不要
    interval(1000)
      .pipe(takeUntilDestroyed())
      .subscribe((n) => (this.seconds = n));

    // 破棄時に実行したい処理も、その場で登録できる
    this.destroyRef.onDestroy(() => console.log('片付け完了'));
  }
}
サンプルコードで身につける(5本) →

学んだ概念を、素朴な例から実務寄りの例まで5つの具体例で確認します。

公式ドキュメントで詳しく ↗