Dawid Ryczko
Dawid Ryczko
Jestem fanem Angulara i TypeScript.
Dawno temu kodowałem w Javie :)
Dec 11, 2019 3 min read

Konstruktor czy ngOnInit w Angularze - constructor vs ngOnInit

thumbnail for this post

Czasami dostaje pytania jaka jest różnica pomiędzy konstruktorem constructor(), a metodą ngOnInit(). Spróbuję krótko wyjaśnić Wasze wątpliwości czy lepiej użyć konstruktora czy ngOnInit w Angularze. Zacznijmy od zdefiniowania czym jest konstruktor i metoda ngOnInit.

Konstruktor

Konstruktor nie jest częścią Angulara. Jest to metoda, która jest dostępna w każdej klasie języka TypeScript. Jest odpowiedzialny za stworzenie instancji klasy i jest to metoda, która wywołuje się jako pierwsza, gdy powstaje obiekt klasy. W Angularze konstruktor używany jest przede wszystkim do wstrzykiwania zależności na przykład angularowych serwisów.

Oczywiście konstruktora w klasie nie musimy posiadać, ale czasami jest to wymagane. Jednym z przypadków jest gdy rozszerzamy (extends) inną klasę.

// Klasa która posiada konstruktor do inicjalizacji
class Animal {
  name: string;
  constructor(name: string) {
    this.name = name;
  }
}

// Klasa która rozszerza Animal musi posiadać konstruktor, 
// aby wywołać konstruktor z klasy Animal i przekazać wartość.
class Dog extends Animal {
  constructor(name: string) {
    super(name);
  }
}
const sam = new Dog("Reksio");

Jest to jeden z prostych przypadków, gdy konstruktor musi zostać zadeklarowany.

ngOnInit

Jest to metoda pochodząca z interfejsu OnInit wbudowanego w Angulara. Jeżeli chcemy używać metody ngOnInit powinniśmy zaimplementować właśnie ten interfejs. Metoda ngOnInit nie jest obowiązkowa i nie musimy jej używać.

@Component({
  selector: "my-app",
  templateUrl: "./app.component.html",
  styleUrls: ["./app.component.css"]
})
export class AppComponent implements OnInit {
  constructor() {}

  ngOnInit() {}
}

Implementacja interfejsu należy do dobrych praktyk, bo i bez tego nasz kod skompiluje się, jeśli tylko zadeklarujemy metodę ngOnInit. Metoda ta należy do Liveceycle Hooks czyli metod, za pomocą których kontrolujemy cykle życia komponentu. Jest ich więcej, ale dzisiaj zajmiemy się tylko ngOnInit.

Metoda ta uruchamiana jest zaraz po tym, jak powstanie cały komponent i zainicjalizowane zostaną pierwsze właściwości komponentu jak pola @Input(). Podobnie jak konstruktor, metoda ngOnInit uruchamia się tylko raz.

Jak używać?

Konstruktor zawsze wywołuje się przed metodą ngOnInit. Co oznacza, że w konstruktorze nie mamy dostępu do pól oznaczonych dekoratorem Input(). Wartości tych pól dostępne będą dopiero w ngOnInit i jest to jedna z ważniejszych różnic.

Konstruktor może nam posłużyć do inicjalizacji prostych zmiennych. Nie umieszczamy tam żadnej skomplikowanej logiki. Jeżeli chcemy wywołać zewnętrzne API, skomplikowane obliczenia zróbmy to w ngOnInit. Najlepszym jednak wyjściem jest użycie konstruktora jako miejsca do wstrzykiwania zależności, a wszelkie pozostałe inicjalizacje danych wykonać w metodzie ngOnInit.

@Component({
  selector: "my-app",
  templateUrl: "./app.component.html",
  styleUrls: ["./app.component.css"]
})
export class AppComponent implements OnInit {

  @Input() item; // Zbindowana wartość będzie dostępna dopiero w ngOnInit
  items: string[];

  // W konstruktorze tylko wstrzykujemy serwisy
  constructor(private httpService: HttpService) {}

  // ngOnInit służy do inicjalizacji danych 
  ngOnInit() {
    this.items = this.httpService.fetchItems();
  }
}

Dodatkowym argumentem za tym aby logikę inicjalizacji komponentu umieszczać w ngOnInit są testy. W przypadku testowania komponentu i umieszczenia logiki w konstruktorze, będziemy musieli zatroszczyć się tą logiką i zainicjalizować ją. Może być to problematyczne gdy chcemy przetestować jedną metodę komponentu i napisać prosty unit test.

Wywoływania konstruktora niestety nie możemy kontrolować, tak jak to możemy robić z ngOnInit w czasie testów.

const instance = new AppComponent();
instance.ngOnInit();

Dlatego warto wszelkie inicjalizacje przeprowadzać w ngOnInit.

Podsumowanie konstruktor vs ngOnInit

  • konstruktor wywołuje się przed ngOnInit i jest konstrukcją TypeScript
  • konstruktor nie jest obowiązkowy, ale służy do wstrzykiwania zależności
  • ngOnInit wywołuje się raz i pochodzi z interfejsu OnInit wbudowanego w Angulara
  • ngOnInit możemy nazwać konstruktorem angularowego komponentu
  • metoda ngOnInit także nie jest obowiązkowa
  • dopiero w ngOnInit mamy dostęp do wartości z pól Input()
  • wszelką logikę zainicjalizujmy w ngOnInit
  • hook ngOnInit możemy ręcznie wywołać w czasie testowania komponentu
  • ngOnInit jest jednym z ośmiu metod do kontrolowania cyklów życia komponentu
comments powered by Disqus