AngularのLifecycle Hooksを理解する

AngularのLifecycle Hooksを理解する

Angularのコンポーネントやディレクティブには Lifecycle Hooks(ライフサイクルフック) という仕組みがあり、コンポーネントの変化にあわせてコールバックを設定できます。これによりコンポーネントのデータやビューの変更時の処理を追加できます。
コンポーネント志向のAngularアプリケーションの構築では、Lifecycle Hooks の理解が不可欠です。

今回は Lifecycle Hooks の基本的な仕組みを紹介します。

Lifecycle Hooksとは

記事の冒頭でも説明したように、Lifecycle Hooks はコンポーネントやディレクティブが変化(作成・変更・破棄)するタイミングで実行されるコールバックメソッドの総称です。

例えば、次のようなケースで利用します。

  • コンポーネントの初期化時にHttpクライアントでデータを取得する。
  • 親コンポーネントの初期化時に、子コンポーネントのDOM要素を取得する。
  • コンポーネントの @Input() で受け取るデータ内容を検証する。
  • 設定したイベントリスナーをコンポーネントが破棄される際に削除する。

Lifecycle Hooksを設定すると、コンポーネント自身が変更を検出したときに自動でコールバックが実行されるため、自前で実行タイミングを設定する手間が省けます。またコンポーネント実装の一貫性を保つことにも繋がります。

Lifecycle Hooksの使い方

ここではコンポーネントの初期化時に実行される ngOnInit メソッドを見てみましょう。
ngOnInit メソッドは、Angular CLIの ng generate component コマンドでコンポーネントを作成するとはじめから適用されています。

import { Component, OnInit } from '@angular/core'; // ①
import { LoggerService } from './logger.service';

@Component({
  ...
})
export class PeekABooComponent implements OnInit { // ②

  constructor(private logger: LoggerService) { }

  ngOnInit() { // ③
    this.log(`OnInit`);
  }

  private log(msg:string){
    this.logger.log(`${nextId++} ${msg}`);
  }
}
  1. @angular/core から OnInit インターフェイスをインポートしています。
  2. コンポーネントのクラスに、OnInit インターフェースを実装します。
  3. OnInit インターフェースを実装すると、ngOnInit メソッドの定義が必要になります。

Lifecycle Hooks は各メソッドを実装するためのインターフェイスが必要です。
インターフェイスの適用後はインターフェイス名の接頭辞に ng を付けた ngXXXX メソッドが定義できます。例えば OnInit インターフェイスだと ngOnInit メソッドとなります。

インターフェイスを適用しなくてもメソッドを定義できますが、Angularスタイルガイドのルールではインターフェイスを必ず指定することになっていますので、忘れずに適用してください。

Lifecycle Hooksの種類

メソッド名目的と実行タイミング
ngOnInit1回目の @Input() でデータバインドされた入力値を初期化後に一度だけ実行します。

Httpクライアントによるデータ取得などを含む、コンポーネントの初期化に関する処理を行います。
ngOnChanges@Input() でデータバインドされた入力値を設定・リセットする際に実行します。この処理は入力値が変更するたびに実行され、現在と過去のプロパティを保持した変更オブジェクト(SimpleChanges)を引数で受け取ります。
ngOnInitメソッドの前に1回実行され、その後は @Input でデータを受け取る度に実行されます。

受け取ったデータ内容を検証する目的で利用します。
ngDoCheckデータの変更を検出するたびに実行します。
ngAfterContentInitコンポーネントまたはディレクティブのあるビューに、ng-contentでコンテンツが挿入された後に実行します。
ngAfterContentCheckedコンポーネントまたはディレクティブに、ng-contentで挿入されたコンテンツの変更を検知した際に実行します。
ngAfterViewInitコンポーネントのビューとその中の子ビュー、またはディレクティブを含むビューを生成した後に実行します。

ビューに存在するDOMを取得したり、子コンポーネントを参照する際に利用します。
ngAfterViewCheckedコンポーネントのビューとその中の子ビュー、またはディレクティブを含むビューの変更を検知した後に実行します。

ビューに存在するDOMや子コンポーネントの変更を監視する際に利用します。
ngOnDestroyコンポーネントまたはディレクティブを破棄する直前に実行します。

RxJSのSubscriptionをunsubscribeしたり、element.removeEventListener を実行するために利用します。

Lifecycle Hooksの実行順序

Lifecycle Hooksは次の順番で実行されます。

  1. ngOnChanges
  2. ngOnInit
  3. ngDoCheck
  4. ngAfterContentInit
  5. ngAfterContentChecked
  6. ngAfterViewInit
  7. ngAfterViewChecked
  8. ngOnDestroy

※その他に ngOnChanges はデータを受け取る度、ngDoCheck は ngOnChages の後にも実行されます。

Lifecycle Hooksのライブデモ

以下のライブデモでLifecycle Hooksの動きを試せます。

https://stackblitz.com/angular/enapoxavrmn?embed=1&file=src/app/app.component.html

一番上のPeek-A-Booセクションで、「Create PeekABooComponent」「Update Hero」「Destroy PeekABooComponent」を順にクリックすると Lifecycle Hooksの実行ログを確認できます。
コードと実行結果を見比べてもらえば、わかりやすいです。

【公式日本語ドキュメント】 コンポーネントライフサイクルへのフック

五十川 洋平(Yohei Isokawa)

五十川 洋平(Yohei Isokawa)

フロントエンドエンジニア/面白法人カヤックなどのWeb制作会社に勤務したのち、故郷の新潟に戻り独立。JSフレームワークAngularやFirebase、Google Cloud Platformを使ったWebアプリ開発が得意。 また、Udemyのプログラミング解説の講師、writer.appの自主開発や上越TechMeetupの主催などを行っています。

プロフィール

©Copyright 2020 Yohei Isokawa All Rights Reserved.