konstruktor oraz lifecycle hooks
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.