Жизненный цикл компонента

Последнее обновление: 13.11.2023

После создания компонента фреймворк Angular вызывает у этого компонента ряд методов, которые представляют различные этапы жизненного цикла. Так, инициализацию компонента можно фигурально выразить следующим образом:

Жизненный цикл компонентов в Angular 17

В процессе обновления компонента также срабатывают некоторые события жизненного цикла:

Жизненный цикл компонентов и события изменения компонента в Angular 17

Итак, компонент проходит следующие этапы жизненного цикла

  • конструктор: сначала выполняется конструктор компонентам

  • 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() не аналогичен конструктору. Конструктор также может выполнять некоторую инициализацию объекта, в то же время что-то сложное в конструкторе делать не рекомендуется. Конструктор должен быть по возможности простым и выполнять самую базовую инициализацию. Что-то более сложное, например, загрузку данных с сервера, которая может занять продолжительное время, лучше делать в методе ngOnInit.

ngOnDestroy

Метод ngOnDestroy() вызывается перед удалением компонента. И в этом методе можно освобождать те используемые ресурсы, которые не удаляются автоматически сборщиком мусора. Здесь также можно удалять подписку на какие-то события элементов DOM, останавливать таймеры и т.д.

ngOnChanges

Метод 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:

OnChanges в Angular 17

В то же время надо отметить, что данный метод вызывается только при изменении входных свойств с декоратором @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";
}

И при обращении к приложению мы получим следующую цепочку вызовов:

Обработка событий жизненного цикла в  Angular 17
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850