この記事ではAngularの「ngOnInit」と「constructor」について
- 「ngOnInit」と「constructor」の違い
などをプログラム例を用いて分かりやすく説明するように心掛けています。ご参考になれば幸いです。
「ngOnInit」と「constructor」の違い
Angularにおいて、ngOnInitとconstructorは呼び出されるタイミングが違うため、異なる目的で使用します。
まず、ngOnInitとconstructorの違いを以下にまとめます(後ほどプログラム例で実際にこれらの違いを確認してみます)。
ngOnInit
- Angularのライフサイクルフックの一部です。
- コンポーネントが作成された直後に一度だけ呼び出されます。もう少し詳しく説明すると、ngOnChangesをコンポーネントに使用している場合、ngOnChangesを呼び出した後に一度だけ呼び出されます。
- コンポーネントの初期化はngOnInitで行います。
constructor
- JavaScript(TypeScript)の一部です。Angularのライフサイクルフックとは関係ありません。
- クラスがインスタンス化される時に常に呼び出されます。つまり、コンポーネント作成途中で呼び出されます。
- コンポーネントの初期化をconstructorで行うのは一般的ではありません。constructorは依存性の注入のために使用します。
- コンポーネントが@Inputデコレーターを持つ場合、@Inputデコレーターで受け取るプロパティはconstructorが呼びされるタイミングではまだ初期化されていないため、constructor内で@Inputデコレーターで受け取るプロパティにアクセスすると、undefinedまたは初期値(設定している場合)が返されます。
「ngOnInit」と「constructor」の違いを説明するプログラム例1
以下に、「Appコンポーネント(app.compomponent.ts)」と「メッセージサービス(message.service.ts)」のプログラム例を示しています。
app.compomponent.ts
import { Component, OnInit } from '@angular/core';
import { MessageService } from './message.service'; // MessageServiceをインポート
@Component({
selector: 'app-root',
template: `<h1>{{title}}</h1>`,
})
export class AppComponent implements OnInit {
title?: string;
// constructorでは、依存性を注入します
constructor(private messageService: MessageService) {
console.log("constructorを呼び出しています");
}
// ngOnInitでは、初期化を行います
ngOnInit() {
console.log("ngOninitを呼び出しています");
this.title = this.messageService.getTitle();
}
}
// ログ
// constructorを呼び出しています
// ngOninitを呼び出しています
message.service.ts
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root',
})
export class MessageService {
private title = 'Hello, Angular!';
constructor() { }
getTitle(): string {
return this.title;
}
}
MessageService
はAppComponentのconstructor内で依存性として注入されます。これにより、AppComponent内でMessageService
のメソッドやプロパティを使用することが可能になります。
ngOnInitではMessageService
のgetTitle
メソッド使用してtitle
プロパティを初期化しています。
また、ブラウザのコンソールに出力されるメッセージに注目すると、「console.log("constructorを呼び出しています")」が実行された後に「console.log("ngOninitを呼び出しています")」が実行されていることを確認することができます。つまり、constructorが呼び出された後にngOnInitが呼び出されています。constructorはコンポーネントの作成途中、ngOnInitはコンポーネントの作成直後に呼び出されるので、この順番は適切です。
補足
MessageServiceは単に「Hello, Angular!」を出力するだけのサービスです。具体的な内容はアプリケーションの要件によります。
ngOnInit」と「constructor」の違いを説明するプログラム例2
以下に、「Appコンポーネント(app.compomponent.ts)」と「子コンポーネント(child.component.ts)」のプログラム例を示しています。このプログラム例では、constructorで@Input
デコレーターで受け取るプロパティ(以下のプログラムでは、childItem
)にアクセスすると、「undefined」が返されてしまうことを説明します。
app.compomponent.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
template: `<app-child [childItem] = 'parentItem' ></app-child>`,
})
export class AppComponent {
parentItem = 'Hello Angular!'
}
child.component.ts
import { Component, Input } from '@angular/core';
@Component({
selector: 'app-child',
template: `{{childItem}}`,
})
export class ChildComponent {
@Input() childItem?: string;
constructor() {
console.log("constructorを呼び出しています");
// constuctorが呼びされるタイミングでは、childItemプロパティの値が設定されていない
console.log("constructor内でのchildItemの値: ", this.childItem); // undefined
}
ngOnInit() {
console.log("ngOninitを呼び出しています");
// ngOnInitが呼び出されるタイミングでは、childItemプロパティの値が設定されている
console.log("ngOnInit内でのchildItemの値: ", this.childItem); // 親コンポーネントからの値が表示される
}
}
// ログ
// constructorを呼び出しています
// constructor内でのchildItemの値: undefined
// ngOninitを呼び出しています
// ngOnInit内でのchildItemの値: Hello Angular!
上記のプログラム例では、@Input
デコレーターで、childItem
という名前のプロパティを定義しています。親コンポーネント側のテンプレートにおいて、「[childItem] = 'parentItem'
」と記述してあるため、childItem
プロパティはparentItem
プロパティの値(Hello Angular!)を受け取っています。
constructor内でchildItemプロパティにアクセスする場合、childItemプロパティはundefinedとなります。これは、constuctorが呼びされるタイミングでは、childItem
プロパティの値が設定されていないためです。
一方、ngOnInitでchildItemプロパティにアクセスする場合、childItemプロパティは親コンポーネント(Appコンポーネント)から受け取った値(Hello Angular!)になっています。これは、ngOnInitが呼び出されるタイミングでは、childItem
プロパティの値が設定されているためです。
本記事のまとめ
この記事ではAngularの「ngOnInit」と「constructor」について、以下の内容を説明しました。
- 「ngOnInit」と「constructor」の違い
お読み頂きありがとうございました。