Hooks de Cycle de Vie
Ordre des Hooks
ngOnChanges- Les propriétés d'entrée changentngOnInit- Composant initialiséngDoCheck- Détection de changementsngAfterContentInit- Contenu projeténgAfterContentChecked- Contenu vérifiéngAfterViewInit- Vue initialiséengAfterViewChecked- Vue vérifiéengOnDestroy- Avant la destruction du composant
ngOnInit
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-user'
})
export class UserComponent implements OnInit {
ngOnInit() {
// Initialiser le composant
// Charger les données, configurer les abonnements
this.loadUsers();
}
loadUsers() {
this.userService.getUsers().subscribe(users => {
this.users = users;
});
}
}
Utiliser pour:
- Chargement initial des données
- Configuration des abonnements
- Logique d'initialisation du composant
ngOnChanges
import { Component, Input, OnChanges, SimpleChanges } from '@angular/core';
@Component({
selector: 'app-user-detail'
})
export class UserDetailComponent implements OnChanges {
@Input() userId!: number;
ngOnChanges(changes: SimpleChanges) {
if (changes['userId']) {
const current = changes['userId'].currentValue;
const previous = changes['userId'].previousValue;
const firstChange = changes['userId'].firstChange;
console.log(`userId changed from ${previous} to ${current}`);
if (!firstChange) {
this.loadUser(current);
}
}
}
}
Utiliser pour:
- Réagir aux changements de
@Input() - Mettre à jour les données dérivées quand les entrées changent
ngOnDestroy
import { Component, OnDestroy } from '@angular/core';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
@Component({
selector: 'app-user'
})
export class UserComponent implements OnDestroy {
private destroy$ = new Subject<void>();
ngOnInit() {
this.userService.getUsers()
.pipe(takeUntil(this.destroy$))
.subscribe(users => this.users = users);
// Ou abonnement manuel
this.subscription = this.userService.getUsers().subscribe();
}
ngOnDestroy() {
// Nettoyage
this.destroy$.next();
this.destroy$.complete();
// Ou
this.subscription?.unsubscribe();
}
}
Utiliser pour:
- Se désabonner des observables
- Nettoyer les timers/intervals
- Retirer les event listeners
- Nettoyer les ressources
ngAfterViewInit
import { Component, ViewChild, ElementRef, AfterViewInit } from '@angular/core';
@Component({
selector: 'app-input-focus',
template: `<input #inputField>`
})
export class InputFocusComponent implements AfterViewInit {
@ViewChild('inputField') inputField!: ElementRef;
ngAfterViewInit() {
// La vue est prête, on peut accéder au DOM
this.inputField.nativeElement.focus();
}
}
Utiliser pour:
- Accéder aux éléments
@ViewChild - Manipulation du DOM
- Initialiser des bibliothèques tierces
ngAfterContentInit
import { Component, ContentChild, AfterContentInit } from '@angular/core';
@Component({
selector: 'app-wrapper',
template: `<ng-content></ng-content>`
})
export class WrapperComponent implements AfterContentInit {
@ContentChild(ChildComponent) child!: ChildComponent;
ngAfterContentInit() {
// Le contenu projeté est prêt
console.log('Child component:', this.child);
}
}
Utiliser pour:
- Accéder aux éléments
@ContentChild - Travailler avec le contenu projeté
ngDoCheck
import { Component, DoCheck } from '@angular/core';
@Component({
selector: 'app-custom-check'
})
export class CustomCheckComponent implements DoCheck {
lastValue: any;
ngDoCheck() {
// Appelé à chaque détection de changement
// Utiliser avec parcimonie - impact sur la performance!
if (this.value !== this.lastValue) {
console.log('Value changed manually detected');
this.lastValue = this.value;
}
}
}
Utiliser pour:
- Détection de changements personnalisée
- Détecter les changements qu'Angular ne détecte pas
- Attention: Appelé très fréquemment
Exemple Complet
@Component({
selector: 'app-lifecycle'
})
export class LifecycleComponent
implements OnInit, OnChanges, AfterViewInit, OnDestroy {
@Input() data: any;
@ViewChild('element') element!: ElementRef;
private destroy$ = new Subject<void>();
constructor() {
console.log('1. Constructor');
}
ngOnChanges(changes: SimpleChanges) {
console.log('2. ngOnChanges', changes);
}
ngOnInit() {
console.log('3. ngOnInit');
this.loadData();
}
ngAfterViewInit() {
console.log('4. ngAfterViewInit');
this.element.nativeElement.focus();
}
ngOnDestroy() {
console.log('5. ngOnDestroy');
this.destroy$.next();
this.destroy$.complete();
}
private loadData() {
this.service.getData()
.pipe(takeUntil(this.destroy$))
.subscribe(data => this.processData(data));
}
}
Bonnes Pratiques
- Utiliser
ngOnInitpour l'initialisation (pas le constructeur) - Toujours implémenter
ngOnDestroypour le nettoyage - Éviter la logique lourde dans
ngDoCheck - Utiliser le pattern
takeUntil()pour se désabonner ngAfterViewInitpour l'accès au DOMngOnChangespour la logique dépendante des entrées