konstruktor oraz lifecycle hooks

constructor-small

omówię:

- czym jest cykl życia komponentu
- najczęściej używaną fazę czyli OnInit
- czemu inicjalizowanie danych w konsktuktorze to nie zawsze najlepszy pomysł

Do inicjalizowania danych w Javie często wykorzystuje się konstruktor.

W Angularze także istnieje byt taki jak konstruktor i działa on praktycznie identycznie jak ten, który jest wykorzystywany w Javie. W kontekście komponentu konstruktor jest wykorzystywany praktycznie jedynie do wstrzyknięcia zależności.

Jeżeli natomiast używasz klasy jako DTO, wtedy inicjalizowanie zmiennych w konstruktorze jest jak najbardziej poprawne.

Jeżeli mówimy o komponencie w Angularze, możemy go porównać do Bean’a ze Springa, który posiada scope prototype. Każde odwołanie do komponentu tworzy jego nową instancję. Tutaj pojawia się ważna lekcja do zapamiętania, będąc w komponencie konstruktora będziesz używać praktycznie tylko do wstrzykiwania zależnośći. Czemu tak się dzieje? Związane jest to z cyklem życia komponentu oraz renderowaniem danych w szablonie HTML.

Wyróżniamy kilka faz życia komponentu. W większości przypadków będą Ci potrzebne trzy z nich (są pogrubione).

Fazy oraz ich kolejność:

– constructor

ngOnChanges

ngOnInit

– ngDoCheck

– ngAfterContentInit

– ngAfterContentChecked

– ngAfterViewInit

– ngAfterViewChecked

ngOnDestroy

Pokażę Ci na prostym przykładzie czemu konstruktor to nie najlepsze miejsce do inicjalizowania danych w kontekście komponentów.

W tym przykładzie wykorzystamy adnotację @Input, służy ona do komunikacji między komponentami. Więcej na ten temat znajdziesz w 4 etapie procesu w lekcji numer 1.

W katalogu app stwórz dwa komponenty:

bad-mood.component.ts, który inicjalizuje zmienną finalMood w konstruktorze oraz

mood.component.ts, który inicjalizuje zmienną finalMood w fazie OnInit

W konsoli/terminalu będąc w ścieżce do głównego folderu projektu wpisz: 

ng g c bad-mood 

oraz 

ng g c mood

bad-mood.component.ts

import { Component, Input } from '@angular/core';

@Component({
selector: 'app-bad-mood',
templateUrl: './bad-mood.component.html',
styleUrls: ['./bad-mood.component.scss']
})
export class BadMoodComponent {

public finalMood: string;

@Input()
public mood: string;

constructor() {
this.finalMood = 'Jestem nieszczęśliwy :( Mój aktualny humor to: ' + this.mood;
}
}

bad-mood.component.html


{{finalMood}}

mood.component.ts

import { Component, Input, OnInit } from '@angular/core';

@Component({
selector: 'app-mood',
templateUrl: './mood.component.html',
styleUrls: ['./mood.component.scss']
})
export class MoodComponent implements OnInit {

public finalMood: string;

@Input()
public mood: string;

ngOnInit() { // uzycie concatenacji z ES6
this.finalMood = `W końcu jestem ${this.mood} :)`;
}
}

mood.component.html


{{finalMood}}

app.component.ts

<app-bad-mood class="mood-section" [mood]="'SZCZĘŚLIWY'"></app-bad-mood>
<br>
<app-mood class="mood-section" [mood]="'SZCZĘŚLIWY'"></app-mood>

Do obu komponentów przekazujemy tą samą wartość, natomiast wynik będzie inny.

Wartość zmiennej finalMood która jest inicjalizowana w konstruktorze jest undefined ponieważ konstruktor wykonuje się jako pierwszy jeszcze przed wyrenderowaniem HTML’a oraz zanim zostaną przekazane wartości w adnotacji @Input()

Jeżeli jeszcze nie wiesz czym jest adnotacja @Input() zachęcam Cię do pobrania materiałów.

Stwórz komponent lifecycle.component.ts. Zaprezentuję Ci w nim w jakiej kolejności i kiedy odpalają się poszczególne fazy. 

W konsoli wpisz: ng g c lifecycle

Przejdź do lifecycle.component.ts

import { Component, Input, OnChanges, OnDestroy, OnInit, SimpleChanges } from '@angular/core';

@Component({
selector: 'app-lifecycle',
templateUrl: './lifecycle.component.html',
styleUrls: ['./lifecycle.component.scss']
})
export class LifecycleComponent implements OnInit, OnChanges {

private static counter = 1;

@Input()
public value: string;

constructor() {
console.log('constructor odpaliłem się jako:', LifecycleComponent.counter, this.value);
LifecycleComponent.counter++;
}

ngOnInit() {
console.log('ngOnInit odpaliłem się jako:', LifecycleComponent.counter, this.value);
LifecycleComponent.counter++;
}

ngOnChanges(changes: SimpleChanges): void {
console.log('ngOnChanges odpaliłem się jako:', LifecycleComponent.counter, this.value);
LifecycleComponent.counter++;
}
}

app.component.ts

<app-bad-mood class="mood-section" [mood]="'SZCZĘŚLIWY'"></app-bad-mood>
<br>
<app-mood class="mood-section" [mood]="'SZCZĘŚLIWY'"></app-mood>
<br>
<app-lifecycle [value]="'wartość przekazanej zmiennej'"></app-lifecycle>

Przejdź do localhost:4200 wciśnij F12 i przejdź do zakładki console.