После создания компонента фреймворк Angular вызывает у этого компонента ряд методов, которые представляют различные этапы жизненного цикла. Так, инициализацию компонента можно фигурально выразить следующим образом:
В процессе обновления компонента также срабатывают некоторые события жизненного цикла:
Итак, компонент проходит следующие этапы жизненного цикла
конструктор: сначала выполняется конструктор компонентам
ngOnChanges: вызывается до метода ngOnInit()
при начальной установке свойств, которые связаны механизмом привязки, а также при любой их переустановке или
изменении их значений. Данный метод в качестве параметра принимает объект класса SimpleChanges
, который содержит предыдущие и текущие значения
свойства. Например, проверка изменений:
ngOnChanges(changes: SimpleChanges) { for (const inputName in changes) { const inputValues = changes[inputName]; console.log(`Previous ${inputName} == ${inputValues.previousValue}`); console.log(`Current ${inputName} == ${inputValues.currentValue}`); console.log(`Is first ${inputName} change == ${inputValues.firstChange}`); } }
ngOnInit: вызывается один раз после того, как Angular инициализирует все входные свойства компонентов их начальными значениями. Выполняется до инициализации шаблона компонента. Это означает, что в этом методе можно обновить состояние компонента на основе его начальных входных значений.
ngDoCheck: вызывается при каждой проверке изменений свойств компонента сразу после методов ngOnChanges
и ngOnInit
ngAfterContentInit: вызывается один раз после метода ngDoCheck()
после того, как инициализированы все вложенные компоненты
ngAfterContentChecked: вызывается фреймворком Angular при проверке изменений содержимого,
которое добавляется в шаблон компонента. Вызывается после метода ngAfterContentInit()
и
после каждого последующего вызова метода ngDoCheck()
.
ngAfterViewInit: вызывается фреймворком Angular после инициализации шаблона компонента, а также шаблона дочерних
компонентов. Вызывается только один раз сразу после первого вызова метода ngAfterContentChecked()
ngAfterViewChecked: вызывается фреймворком Angular после проверки на изменения в шаблоне компонента, а также проверки
шаблона дочерних компонентов. Вызывается после первого вызова метода ngAfterViewInit()
и после каждого последующего вызова ngAfterContentChecked()
ngOnDestroy: вызывается перед тем, как фреймворк Angular удалит компонент.
afterRender и afterNextRender позволяют выполнить код после рендеринга компонента. Код этих функций будет вызываться после того, как Angular завершит рендеринг всех компонентов на странице в DOM. Эти функции относятся ко всему приложению в целом, а не к отдельным компонентам. Поэтому они перехватывают момент посое рендеринга всего приложения, всех его компонентов.
Большая часть подобных методов определена в отдельном интерфейсе, который называется по имени метода без префикса "ng". Например, метод ngOnInit
определен
в интерфейсе OnInit
. Поэтому, если мы хотим отслеживать какие-то этапы жизненного цикла компонента, то класс компонента должен применять соответствующие интерфейсы:
import { Component, OnInit, OnDestroy } from "@angular/core"; @Component({ selector: "my-app", standalone: true, template: <p>Hello METANIT.COM</p>` }) export class AppComponent implements OnInit, OnDestroy { constructor(){ console.log("constructor"); } ngOnInit() { console.log("onInit"); } ngOnDestroy() { console.log("onDestroy"); } }
Метод ngOnInit()
применяется для какой-то комплексной инициализации компонента. Здесь можно выполнять загрузку данных с сервера или из других источников данных.
ngOnInit()
не аналогичен конструктору. Конструктор также может выполнять некоторую инициализацию объекта, в то же время что-то сложное в конструкторе
делать не рекомендуется. Конструктор должен быть по возможности простым и выполнять самую базовую инициализацию. Что-то более сложное, например, загрузку данных с сервера,
которая может занять продолжительное время, лучше делать в методе ngOnInit
.
Метод ngOnDestroy()
вызывается перед удалением компонента. И в этом методе можно освобождать те используемые ресурсы, которые не удаляются автоматически сборщиком мусора.
Здесь также можно удалять подписку на какие-то события элементов DOM, останавливать таймеры и т.д.
Метод ngOnChanges()
вызывается перед методом ngOnInit()
и при изменении свойств в привязке. С помощью параметра SimpleChanges
в методе можно получить
текущее и предыдущее значение измененного свойства. Например, пусть у нас будет следующий дочерний компонент ChildComponent:
import { Component, Input, OnInit, OnChanges, SimpleChanges } from "@angular/core"; @Component({ selector: "child-comp", standalone: true, template: `<p>Привет {{name}}</p>` }) export class ChildComponent implements OnInit, OnChanges { @Input() name: string = ""; constructor(){ console.log("constructor"); } ngOnInit() { console.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); console.log(`${propName}: currentValue = ${cur}, previousValue = ${prev}`); } } }
И пусть этот компонент используется в главном компоненте AppComponent:
import { Component, OnChanges, SimpleChanges} from "@angular/core"; import { FormsModule } from "@angular/forms"; import { ChildComponent} from "./child.component"; @Component({ selector: "my-app", standalone: true, imports: [FormsModule, ChildComponent], template: `<child-comp [name]="name"></child-comp> <input type="text" [(ngModel)]="name" /> <input type="number" [(ngModel)]="age" />` }) export class AppComponent implements OnChanges { name ="Tom"; age = 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); console.log(`${propName}: currentValue = ${cur}, previousValue = ${prev}`); } } }
То есть значение для свойства 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", standalone: true, template: `<p>Привет {{name}}</p>` }) export class ChildComponent implements OnInit, DoCheck, OnChanges, AfterContentInit, AfterContentChecked, AfterViewChecked, AfterViewInit { @Input() name: string = ""; count= 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"; import { FormsModule } from "@angular/forms"; import { ChildComponent} from "./child.component"; @Component({ selector: "my-app", standalone: true, imports: [FormsModule, ChildComponent], template: `<child-comp [name]="name"></child-comp> <input type="text" [(ngModel)]="name" />` }) export class AppComponent{ name = "Tom"; }
И при обращении к приложению мы получим следующую цепочку вызовов: