Aller au contenu principal

Hooks de Cycle de Vie

Ordre des Hooks

  1. ngOnChanges - Les propriétés d'entrée changent
  2. ngOnInit - Composant initialisé
  3. ngDoCheck - Détection de changements
  4. ngAfterContentInit - Contenu projeté
  5. ngAfterContentChecked - Contenu vérifié
  6. ngAfterViewInit - Vue initialisée
  7. ngAfterViewChecked - Vue vérifiée
  8. ngOnDestroy - 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 ngOnInit pour l'initialisation (pas le constructeur)
  • Toujours implémenter ngOnDestroy pour le nettoyage
  • Éviter la logique lourde dans ngDoCheck
  • Utiliser le pattern takeUntil() pour se désabonner
  • ngAfterViewInit pour l'accès au DOM
  • ngOnChanges pour la logique dépendante des entrées