Angular - Cycle de vie d'un composant

Dans cet article, vous allez découvrir le cycle de vie d'un composant Angular en détail.

Définition

Le cycle de vie correspond aux différentes étapes de la vie d'une instance. Il débute toujours par une instanciation et termine par la destruction de l'instance, donc la désallocation des ressources mémoire qui lui sont affectées.

Un hook (crochet) est une méthode qui s'exécute lors de certains événements liés au cycle de vie. Cela permet à votre app Angular d'exécuter du code JavaScript lors de ces événements.

De plus, cela peut s'avérer utile, par exemple pour lancer un appel vers une API au chargement d'une page ou bien pour libérer une ressource lors de la destruction de l'instance du composant.

Les étapes du cycle de vie d'un composant

Cycle de vie d'un composant Angular

Par exemple, sur ce diagramme, vous observez l'ordre d'enchainement des hooks en vous fiant aux numéros inscrits à côté de chaque étape.

Voici un détail de chacun de ces hooks, dans l'ordre où ils sont appelés.

1. Le constructeur

Le cycle commence par l'appel du constructeur, juste après l'instanciation du Component.

Dans le constructeur, placez uniquement les initialisations de variable locales avec des valeurs simples.

1
2
3
4
constructor() {
    this.title = "Constructor";
    this.details = "Life cycle component";
}
any.component.ts

Ainsi, ne placez aucune initialisation complexe dans le constructeur. Vous voulez des composant qui se construisent sans consommer beaucoup de ressources et de manière sûre.

2. Détecter les changements d'Input

Immédiatement après le constructeur, Angular appelle le hook ngOnChanges(). Il est également appelé après chaque changement d'une des propriétés passées en Input.

1
2
3
4
5
6
7
8
9
10
11
@Input() lastname: string;

constructor() {}

ngOnChanges() {
  this.uppercase(this.lastname);
}

private uppercase(input: string) {
  input = input.toUpperCase();
}
OnChanges.component.ts

3. Initialiser le composant

Utilisez la méthode ngOnInit() dans les 2 cas suivants :

  • Vous voulez mettre en place une initialisation complexe (donc hors du constructeur), typiquement appeler une API qui charge les données de votre page.
  • Vous devez modifier l'état de votre component après le chargement des attributs passés en @Input
1
2
3
4
5
6
7
8
9
10
11
12
13
    studentList: Array<any>;

    constructor(private studentService: StudentService){}

    ngOnInit(){
        this.getStudent();
    }

    getStudent(){
        this.studentService
            .getStudentsFromService()
            .subscribe(students =>  this.studentList = students);
    }
OnInit.component.ts

4. Réagir à tous les changements du DOM

Vous souhaitez réagir à un changement du DOM qui est indétectable par vos autres hooks ?

Dans ce cas vous devrez utiliser la méthode ngDoCheck()

Cette méthode vous permet de réagir à tout changement dans la page qui ne serait pas détecté par le framework.

Attention ! Ne l'utilisez pas plus que nécessaire : cette méthode coûte énormément de ressources et peut donc diminuer les performances globales de votre application.

De ce fait, vous ne verrez pas beaucoup ce hook !

5. Détecter les changements de ng-content

La méthode ngAfterContentInit() est déclenchée lorsque le contenu de la balise ng-content est reçu pour la première fois.

Exemple ContentChild

1
2
3
<app-child-component>
    <div #name >Krishna</div>
</app-child-component>
parent.component.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Component({
    selector: 'app-child-component',
    template: '<ng-content></ng-content>',
    styleUrls: ['./new-component.component.scss']
})
export class ChildComponent implements AfterContentInit  {
  
    @ContentChild('name') nameRef: ElementRef;
  
    ngAfterContentInit(): void {
  
        console.log(this.nameRef);
    }
}
child.component.ts

Exemple ContentChildren

1
2
3
4
<app-child-component>
    <div #name >Mahesh</div>
    <div #name >Krishna</div>
</app-child-component>
parent.component.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Component({
    selector: 'app-child-component',
    template: '<ng-content></ng-content>',
    styleUrls: ['./new-component.component.scss']
})
export class ChildComponent implements AfterContentInit  {
  
    @ContentChildren('name') nameRef: QueryList<ElementRef>;
  
    ngAfterContentInit(): void {
  
        console.log(this.nameRef);
    }
}
child.component.ts

Il y a aussi le hook ngAfterContentchecked() qui est déclenché à chaque fois que le contenu de cette balise est modifié dynamiquement.

6. Accéder au DOM

La méthode ngAfterViewInit() est déclenchée lorsque le contenu des variables décorées par @ViewChild ou @ViewChildren est reçu pour la première fois.

Exemple ViewChild

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Component({
    selector: 'app-child-component',
    template: '<div #age> 20 </div>',
    styleUrls: ['./new-component.component.scss']
  })
export class ChildComponent implements AfterViewInit  {
  
    @ViewChild('age') ageRef: ElementRef;
  
    ngAfterViewInit(): void {
  
      console.log(this.ageRef);
    }
}
child.component.ts

Exemple ViewChildren

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Component({
    selector: 'app-child-component',
    template: `<div #age>20 </div>
                <div #age>24 </div>`,
    styleUrls: ['./new-component.component.scss']
  })
export class ChildComponent implements AfterViewInit  {
  
    @ViewChildren('age') ageRef: QueryList<ElementRef>;
  
    ngAfterViewInit(): void {
  
      console.log(this.ageRef);
    }
}
child.component.ts

ngAfterViewchecked() est déclenchée à chaque fois que le contenu de ces variables est modifié.

7. Détruire l'instance proprement

Enfin le hook ngOnDestroy() vous permet de libérer des ressources avant la destruction de l'instance du composant.

  • Appliquez unsubscribe() aux Observables auxquels le composant est souscrit.
  • Arrêtez vos timers.
  • Désouscrivez-vous également des Promise et callbacks qui viennent de services partageables.

En dernier lieu, ngOnDestroy() peut aussi servir à envoyer un Event pour signaler la destruction à un autre Component.

1
2
3
4
5
6
7
8
9
10
11
12
13
export class OnDestroyComponent implements OnInit {

    subscription : Subscription;
  
    ngOnInit(): void {
      var observable = interval(1000);
      this.subscription = observable.subscribe(x => console.log(x));
    }
  
    ngOnDestroy(): void {
      this.subscription.unsubscribe();
    }
}
OnDestroy.component.ts
La prochaine étape, quand vous êtes à l'aise avec le concept de composants : Les services Angular.

Conclusion

Nous venons de voir toutes les étapes d'un cycle de vie d'un Component et les hooks qui y sont associés.

Si il vous reste des questions, n'hésitez pas à nous contacter via cette page !

Sources