Какой цикл жизни у компонентов?
В Angular каждый компонент проходит через определённый жизненный цикл, начиная с его создания и заканчивая уничтожением. Angular предоставляет набор специальных методов-хуков, которые автоматически вызываются фреймворком на разных этапах жизненного цикла компонента или директивы. Эти хуки реализуются через соответствующие интерфейсы, определённые в пакете @angular/core.
Ниже приведены все основные хуки жизненного цикла компонента, порядок их вызова, особенности и практическое применение.
1. constructor()
-
Когда вызывается: при создании экземпляра компонента классом Angular.
-
Что делать: инициализация полей, внедрение зависимостей через DI.
-
Не использовать: доступ к DOM, @Input() значениям или шаблонным переменным — они еще не доступны.
constructor(private service: MyService) {
console.log('constructor');
}
2. ngOnChanges(changes: SimpleChanges)
-
Интерфейс: OnChanges
-
Когда вызывается: при первом присвоении значения @Input() и при каждом последующем его изменении.
-
Что делает: позволяет реагировать на изменение входных данных.
@Input() userId: number;
ngOnChanges(changes: SimpleChanges) {
if (changes\['userId'\]) {
console.log('userId изменился', changes\['userId'\].currentValue);
}
}
Важно: вызывается даже до ngOnInit() при первом присваивании значения.
3. ngOnInit()
-
Интерфейс: OnInit
-
Когда вызывается: один раз после инициализации @Input() параметров и до первого отображения компонента.
-
Что делать: инициализация данных, начало загрузки данных с сервера, подписки.
ngOnInit() {
this.service.loadUser(this.userId).subscribe(...);
}
Отличие от конструктора: ngOnInit() вызывается после установки всех @Input() свойств, constructor() — до.
4. ngDoCheck()
-
Интерфейс: DoCheck
-
Когда вызывается: при каждом цикле обнаружения изменений (change detection).
-
Что делает: позволяет реализовать свою собственную логику отслеживания изменений, альтернативную OnChanges.
ngDoCheck() {
console.log('ngDoCheck вызывается при каждом цикле обнаружения изменений');
}
Часто используется в сочетании с KeyValueDiffers или IterableDiffers для сравнения сложных объектов.
5. ngAfterContentInit()
-
Интерфейс: AfterContentInit
-
Когда вызывается: один раз после вставки контента (проекции) через <ng-content>.
-
Что делать: доступ к контенту, переданному из родителя.
ngAfterContentInit() {
console.log('ngAfterContentInit: контент проецирован');
}
6. ngAfterContentChecked()
-
Интерфейс: AfterContentChecked
-
Когда вызывается: после каждого цикла обнаружения изменений во вставленном контенте.
-
Что делать: логирование или синхронизация состояния с содержимым <ng-content>.
ngAfterContentChecked() {
console.log('ngAfterContentChecked');
}
7. ngAfterViewInit()
-
Интерфейс: AfterViewInit
-
Когда вызывается: один раз после инициализации шаблонных представлений и дочерних компонентов.
-
Что делать: доступ к @ViewChild(), @ViewChildren(), взаимодействие с DOM, инициализация сторонних библиотек.
@ViewChild('myDiv') div!: ElementRef;
ngAfterViewInit() {
console.log(this.div.nativeElement.innerText);
}
Не используйте изменение свойств, влияющих на шаблон — это вызовет ExpressionChangedAfterItHasBeenCheckedError.
8. ngAfterViewChecked()
-
Интерфейс: AfterViewChecked
-
Когда вызывается: после каждого цикла обнаружения изменений во вьюхе.
-
Что делать: синхронизация с вьюхой, производительность, логгинг.
ngAfterViewChecked() {
console.log('ngAfterViewChecked');
}
9. ngOnDestroy()
-
Интерфейс: OnDestroy
-
Когда вызывается: перед уничтожением компонента (удаление из DOM).
-
Что делать: отписка от подписок, очистка таймеров, удаление слушателей, уничтожение сервисов.
private sub!: Subscription;
ngOnInit() {
this.sub = this.service.getData().subscribe(...);
}
ngOnDestroy() {
this.sub.unsubscribe();
console.log('Компонент уничтожен');
}
Порядок вызова хуков
Если представить жизненный цикл как последовательность шагов, порядок будет следующим:
- **constructor
** - **ngOnChanges (если есть @Input())
** - **ngOnInit
** - **ngDoCheck
** - **ngAfterContentInit
** - **ngAfterContentChecked
** - **ngAfterViewInit
** - **ngAfterViewChecked
**
Далее при каждом цикле change detection вызываются:
-
ngDoCheck
-
ngAfterContentChecked
-
ngAfterViewChecked
Перед удалением компонента вызывается:
- ngOnDestroy
Пример: Полный жизненный цикл
@Component({ ... })
export class DemoComponent implements
OnInit,
OnChanges,
DoCheck,
AfterContentInit,
AfterContentChecked,
AfterViewInit,
AfterViewChecked,
OnDestroy {
@Input() data: any;
constructor() {
console.log('constructor');
}
ngOnChanges(changes: SimpleChanges) {
console.log('ngOnChanges', changes);
}
ngOnInit() {
console.log('ngOnInit');
}
ngDoCheck() {
console.log('ngDoCheck');
}
ngAfterContentInit() {
console.log('ngAfterContentInit');
}
ngAfterContentChecked() {
console.log('ngAfterContentChecked');
}
ngAfterViewInit() {
console.log('ngAfterViewInit');
}
ngAfterViewChecked() {
console.log('ngAfterViewChecked');
}
ngOnDestroy() {
console.log('ngOnDestroy');
}
}
Дополнительные замечания
-
Жизненный цикл запускается повторно при каждом обновлении данных, кроме constructor, ngOnInit, ngAfterViewInit, инициализируемых только один раз.
-
Переупорядочивать методы жизненного цикла нельзя — Angular сам определяет порядок вызова.
-
Интерфейсы не обязательны, но добавляют типизацию и явность.
-
Сокращение нагрузки: избегайте тяжёлых операций в ngDoCheck, ngAfterViewChecked, потому что они вызываются часто.
Жизненный цикл компонента в Angular — это основа управления его состоянием, взаимодействия с родительскими и дочерними компонентами, а также работы с DOM и асинхронными процессами. Каждый хук предназначен для конкретной задачи и должен использоваться строго по назначению для обеспечения правильного поведения и производительности приложения.