Жизненный цикл компонента¶
После создания компонента фреймворк Angular вызывает у этого компонента ряд методов, которые представляют различные этапы жизненного цикла:
ngOnChanges
: вызывается до методаngOnInit()
при начальной установке свойств, которые связаны механизмом привязки, а также при любой их переустановке или изменении их значений. Данный метод в качестве параметра принимает объект классаSimpleChanges
, который содержит предыдущие и текущие значения свойства.ngOnInit
: вызывается один раз после установки свойств компонента, которые участвуют в привязке. Выполняет инициализацию компонентаngDoCheck
: вызывается при каждой проверке изменений свойств компонента сразу после методовngOnChanges
иngOnInit
ngAfterContentInit
: вызывается один раз после методаngDoCheck()
после вставки содержимого в представление компонента кода htmlngAfterContentChecked
: вызывается фреймворком Angular при проверке изменений содержимого, которое добавляется в представление компонента. Вызывается после методаngAfterContentInit()
и после каждого последующего вызова методаngDoCheck()
.ngAfterViewInit
: вызывается фреймворком Angular после инициализации представления компонента, а также представлений дочерних компонентов. Вызывается только один раз сразу после первого вызова методаngAfterContentChecked()
ngAfterViewChecked
: вызывается фреймворком Angular после проверки на изменения в представлении компонента, а также проверки представлений дочерних компонентов. Вызывается после первого вызова методаngAfterViewInit()
и после каждого последующего вызоваngAfterContentChecked()
ngOnDestroy
: вызывается перед тем, как фреймворк Angular удалит компонент.
Каждый такой метод определен в отдельном интерфейсе, который называется по имени метода без префикса ng
. Например, метод ngOnInit
определен в интерфейсе OnInit
. Поэтому, если мы хотим отслеживать какие-то этапы жизненного цикла компонента, то класс компонента должен применять соответствующие интерфейсы:
import { Component, OnInit, OnDestroy } from '@angular/core'
@Component({
selector: 'my-app',
template: ` <p>Hello Angular 2</p> `,
})
export class AppComponent implements OnInit, OnDestroy {
name: string = 'Tom'
constructor() {
this.log(`constructor`)
}
ngOnInit() {
this.log(`onInit`)
}
ngOnDestroy() {
this.log(`onDestroy`)
}
private log(msg: string) {
console.log(msg)
}
}
ngOnInit¶
Метод ngOnInit()
применяется для какой-то комплексной инициализации компонента. Здесь можно выполнять загрузку данных с сервера или из других источников данных.
ngOnInit()
не аналогичен конструктору. Конструктор также может выполнять некоторую инициализацию объекта, в то же время что-то сложное в конструкторе делать не рекомендуется. Конструктор должен быть по возможности простым и выполнять самую базовую инициализацию. Что-то более сложное, например, загрузку данных с сервера, которая может занять продолжительное время, лучше делать в методе ngOnInit
.
ngOnDestroy¶
Метод ngOnDestroy()
вызывается перед удалением компонента. И в этом методе можно освобождать те используемые ресурсы, которые не удаляются автоматически сборщиком мусора. Здесь также можно удалять подписку на какие-то события элементов DOM, останавливать таймеры и т. д.
ngOnChanges¶
Метод ngOnChanges()
вызывается перед методом ngOnInit()
и при изменении свойств в привязке. С помощью параметра SimpleChanges
в методе можно получить текущее и предыдущее значение измененного свойства. Например, пусть у нас будет следующий дочерний компонент:
import {
Component,
Input,
OnInit,
OnChanges,
SimpleChanges,
} from '@angular/core'
@Component({
selector: 'child-comp',
template: ` <p>Привет {{ name }}</p> `,
})
export class ChildComponent implements OnInit, OnChanges {
@Input() name: string
constructor() {
this.log(`constructor`)
}
ngOnInit() {
this.log(`onInit`)
}
ngOnChanges(changes: SimpleChanges) {
for (let propName in changes) {
let chng = changes[propName]
let cur = JSON.stringify(chng.currentValue)
let prev = JSON.stringify(chng.previousValue)
this.log(
`${propName}: currentValue = ${cur}, previousValue = ${prev}`
)
}
}
private log(msg: string) {
console.log(msg)
}
}
И пусть этот компонент используется в главном компоненте:
import {
Component,
OnChanges,
SimpleChanges,
} from '@angular/core'
@Component({
selector: 'my-app',
template: `
<child-comp [name]="name"></child-comp>
<input type="text" [(ngModel)]="name" />
<input type="number" [(ngModel)]="age" />
`,
})
export class AppComponent implements OnChanges {
name: string = 'Tom'
age: number = 25
ngOnChanges(changes: SimpleChanges) {
for (let propName in changes) {
let chng = changes[propName]
let cur = JSON.stringify(chng.currentValue)
let prev = JSON.stringify(chng.previousValue)
this.log(
`${propName}: currentValue = ${cur}, previousValue = ${prev}`
)
}
}
private log(msg: string) {
console.log(msg)
}
}
То есть значение для свойства name
передается в дочерний компонент ChildComponent
из главного — AppComponent
. Причем в главном компоненте тоже реализован метод ngOnChanges()
.
И если мы запустим приложение, то сможем заметить, что при каждом изменении свойства name
в главном компоненте вызывается метод ngOnChanges
:
В то же время надо отметить, что данный метод вызывается только при изменении входных свойств с декоратором @Input
. Поэтому изменение свойства age
в AppComponent
здесь не будет отслеживаться.
Реализация всех методов¶
Определим следующий дочерний компонент:
import {
Component,
Input,
OnInit,
DoCheck,
OnChanges,
AfterContentInit,
AfterContentChecked,
AfterViewChecked,
AfterViewInit,
} from '@angular/core'
@Component({
selector: 'child-comp',
template: ` <p>Привет {{ name }}</p> `,
})
export class ChildComponent
implements
OnInit,
DoCheck,
OnChanges,
AfterContentInit,
AfterContentChecked,
AfterViewChecked,
AfterViewInit {
@Input() name: string
count: number = 1
ngOnInit() {
this.log(`ngOnInit`)
}
ngOnChanges() {
this.log(`OnChanges`)
}
ngDoCheck() {
this.log(`ngDoCheck`)
}
ngAfterViewInit() {
this.log(`ngAfterViewInit`)
}
ngAfterViewChecked() {
this.log(`ngAfterViewChecked`)
}
ngAfterContentInit() {
this.log(`ngAfterContentInit`)
}
ngAfterContentChecked() {
this.log(`ngAfterContentChecked`)
}
private log(msg: string) {
console.log(this.count + '. ' + msg)
this.count++
}
}
И используем этот компонент в главном компоненте:
import { Component } from '@angular/core'
@Component({
selector: 'my-app',
template: `
<child-comp [name]="name"></child-comp>
<input type="text" [(ngModel)]="name" />
`,
})
export class AppComponent {
name: string = 'Tom'
}
И при обращении к приложению мы получим следующую цепочку вызовов: