Перейти к содержанию

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

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

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

  • ngOnChanges: вызывается до метода ngOnInit() при начальной установке свойств, которые связаны механизмом привязки, а также при любой их переустановке или изменении их значений. Данный метод в качестве параметра принимает объект класса SimpleChanges, который содержит предыдущие и текущие значения свойства.
  • ngOnInit: вызывается один раз после установки свойств компонента, которые участвуют в привязке. Выполняет инициализацию компонента
  • ngDoCheck: вызывается при каждой проверке изменений свойств компонента сразу после методов ngOnChanges и ngOnInit
  • ngAfterContentInit: вызывается один раз после метода ngDoCheck() после вставки содержимого в представление компонента кода html
  • ngAfterContentChecked: вызывается фреймворком Angular при проверке изменений содержимого, которое добавляется в представление компонента. Вызывается после метода ngAfterContentInit() и после каждого последующего вызова метода ngDoCheck().
  • ngAfterViewInit: вызывается фреймворком Angular после инициализации представления компонента, а также представлений дочерних компонентов. Вызывается только один раз сразу после первого вызова метода ngAfterContentChecked()
  • ngAfterViewChecked: вызывается фреймворком Angular после проверки на изменения в представлении компонента, а также проверки представлений дочерних компонентов. Вызывается после первого вызова метода ngAfterViewInit() и после каждого последующего вызова ngAfterContentChecked()
  • ngOnDestroy: вызывается перед тем, как фреймворк Angular удалит компонент.

Каждый такой метод определен в отдельном интерфейсе, который называется по имени метода без префикса ng. Например, метод ngOnInit определен в интерфейсе OnInit. Поэтому, если мы хотим отслеживать какие-то этапы жизненного цикла компонента, то класс компонента должен применять соответствующие интерфейсы:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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 в методе можно получить текущее и предыдущее значение измененного свойства. Например, пусть у нас будет следующий дочерний компонент:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
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);
    }
}

И пусть этот компонент используется в главном компоненте:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
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 здесь не будет отслеживаться.

Реализация всех методов

Определим следующий дочерний компонент:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
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++;
    }
}

И используем этот компонент в главном компоненте:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
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';
}

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

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

Комментарии