Różnica między konstruktorem a ngOnInit

1071

Angular ngOnInitdomyślnie zapewnia hak cyklu życia .

Dlaczego warto ngOnInitkorzystać, jeśli już mamy constructor?

Haseena PA
źródło
11
hej, sprawdź moją odpowiedź, która wyjaśnia różnicę z perspektywy wewnętrznych działań Angulara
Max Koretskyi
1
@MaximKoretskyi, twój link jest martwy.
Yash Capoor

Odpowiedzi:

1107

ConstructorTo domyślna metoda klasy, który jest wykonywany, gdy klasa jest tworzony i zapewnia prawidłowe inicjalizacji pól w klasie i jej podklasy. Angular, lub lepiej Dependency Injector (DI), analizuje parametry konstruktora, a gdy tworzy nową instancję, wywołując new MyClass(), próbuje znaleźć dostawców pasujących do typów parametrów konstruktora, rozwiązuje je i przekazuje do konstruktora, jak

new MyClass(someArg);

ngOnInit to hak cyklu życia wywoływany przez Angular w celu wskazania, że ​​Angular został zakończony podczas tworzenia komponentu.

OnInitAby go użyć, musimy zaimportować w ten sposób (w rzeczywistości wdrożenie OnInitnie jest obowiązkowe, ale uważane za dobrą praktykę):

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

aby użyć metody make nas z metody OnInit, musimy zaimplementować klasę w następujący sposób:

export class App implements OnInit {
  constructor() {
     // Called first time before the ngOnInit()
  }

  ngOnInit() {
     // Called after the constructor and called  after the first ngOnChanges() 
  }
}

Zaimplementuj ten interfejs, aby wykonać niestandardową logikę inicjowania po zainicjowaniu właściwości związanych z danymi dyrektywy. ngOnInit jest wywoływany zaraz po pierwszym sprawdzeniu właściwości związanych z dyrektywą, a przed sprawdzeniem któregokolwiek z jego elementów potomnych. Jest on wywoływany tylko raz podczas tworzenia instancji dyrektywy.

Najczęściej używamy ngOnInitdo wszystkich inicjalizacji / deklaracji i unikamy rzeczy do pracy w konstruktorze. Konstruktor powinien być używany tylko do inicjowania członków klasy, ale nie powinien wykonywać rzeczywistej „pracy”.

Więc powinieneś użyć, constructor()aby skonfigurować Dependency Injection i niewiele więcej. ngOnInit () jest lepszym miejscem do „rozpoczęcia” - tam gdzie / kiedy są rozwiązywane powiązania komponentów.

Aby uzyskać więcej informacji, patrz tutaj:

Pardeep Jain
źródło
62
Dokładnie, większość (lub nawet wszystkie) języki oparte na klasach mają konstruktory, aby zapewnić właściwą kolejność inicjalizacji, szczególnie klas, które rozszerzają inne klasy, w których mogą pojawić się dość trudne problemy, takie jak pola końcowe (nie wiem, czy TS je ma) i podobne. Konstruktory nie są powiązane z Angular2, są one funkcją TypeScript. Haki cyklu życia są wywoływane przez Angulara po pewnym zainicjowaniu lub gdy wydarzy się jakieś zdarzenie, aby umożliwić komponentowi działanie w określonych sytuacjach i dać mu szansę na wykonanie pewnych zadań w odpowiednim czasie.
Günter Zöchbauer
12
W angular.io/docs/ts/latest/guide/server-communication.html znajduje się cytat blokowy, który wyjaśnia również: „Składniki są łatwiejsze do testowania i debugowania, gdy ich konstruktory są proste i wykonują całą prawdziwą pracę (szczególnie wywołując metodę serwer zdalny) jest obsługiwany w osobnej metodzie. ” - W tym przypadku tą metodą jest ngOnInit ()
yoonjesung
3
to hak cyklu życia wywoływany przez Angular2, aby wskazać, że Angular został zakończony podczas tworzenia komponentu. - to nie do końca tak. sygnalizuje, że zainicjował wiązania. Komponent jest tworzony wcześniej. Zobacz moją odpowiedź
Max Koretskyi
22
Podobnie jak w przypadku wszystkich „najlepszych praktyk”, myślę, że dobrym pomysłem byłoby również wyjaśnienie, dlaczego nie powinieneś wykonywać „pracy” w konstruktorze. Ten artykuł prowadzony przez zespół Angular jest gęsty, ale może pomóc: misko.hevery.com/code-reviewers-guide/… Ponadto mniejszą wagę należy przypisywać inkantacjom wymaganym do wdrożenia OnInit (łatwo go znaleźć) i więcej na temat krytyczny fakt, że powiązania danych nie są dostępne w konstruktorze.
Reikim,
2
Jeśli tryb ścisły jest prawdziwy w tsconfig.jsonpliku podobnym "strict": true, musisz zainicjować członków klasy w constructor, a nie w ngOnitpodobnym FormGroup.
Rohit Sharma
169

Artykuł Zasadnicza różnica między konstruktorem a ngOnInit w Angular bada różnicę z wielu perspektyw. Ta odpowiedź zawiera najważniejsze wyjaśnienie różnicy związane z procesem inicjowania komponentu, które pokazuje także inne użycie.

Kątowy proces ładowania początkowego składa się z dwóch głównych etapów:

  • konstruowanie drzewa komponentów
  • wykrywanie zmiany biegu

Konstruktor komponentu jest wywoływany, gdy Angular konstruuje drzewo komponentów. Wszystkie haki cyklu życia są wywoływane jako część wykrywania zmian w trakcie działania.

Kiedy Angular buduje drzewo komponentów, wtryskiwacz modułu głównego jest już skonfigurowany, aby można było wstrzykiwać dowolne globalne zależności. Ponadto, gdy Angular tworzy instancję klasy elementu podrzędnego, wtryskiwacz dla komponentu nadrzędnego jest już skonfigurowany, więc można wstrzykiwać dostawców zdefiniowanych dla komponentu nadrzędnego, w tym samego komponentu nadrzędnego. Konstruktory komponentów to jedyna metoda wywoływana w kontekście wtryskiwacza, więc jeśli potrzebujesz jakiejkolwiek zależności, jest to jedyne miejsce na uzyskanie tych zależności.

Kiedy Angular rozpoczyna wykrywanie zmian, drzewo komponentów jest budowane i wywoływane są konstruktory wszystkich komponentów w drzewie. Również węzły szablonu każdego komponentu są dodawane do DOM. @InputMechanizm komunikacji jest przetwarzany podczas wykrywania zmian, więc nie można oczekiwać, aby mieć właściwości dostępnych w konstruktorze. Będzie dostępny po ngOnInit.

Zobaczmy szybki przykład. Załóżmy, że masz następujący szablon:

<my-app>
   <child-comp [i]='prop'>

Tak więc Angular rozpoczyna ładowanie aplikacji. Jak powiedziałem, najpierw tworzy klasy dla każdego komponentu. To nazywa MyAppComponentkonstruktorem. Tworzy również węzeł DOM, który jest elementem głównym my-appkomponentu. Następnie przechodzi do utworzenia elementu hosta dla konstruktora child-compi wywołania go ChildComponent. Na tym etapie tak naprawdę nie dotyczy to iwiązania wejściowego i żadnych haków cyklu życia. Po zakończeniu tego procesu Angular kończy się następującym drzewem widoków komponentów:

MyAppView
  - MyApp component instance
  - my-app host element data
       ChildCompnentView
         - ChildComponent component instance
         - child-comp host element data  

Dopiero wtedy uruchamiane są wykrywanie zmian i aktualizacje powiązań dla my-appwywołań i ngOnInitklasy MyAppComponent. Następnie przechodzi do aktualizacji powiązań dla child-compi wywołuje ngOnInitklasę ChildComponent.

Możesz wykonać logikę inicjalizacji albo w konstruktorze, albo w ngOnInitzależności od potrzeb. Na przykład artykuł Oto, jak uzyskać ViewContainerRef przed oceną zapytania @ViewChild, pokazuje, jaki typ logiki inicjalizacji może być wymagany w konstruktorze.

Oto kilka artykułów, które pomogą Ci lepiej zrozumieć ten temat:

Max Koretskyi
źródło
33
to powinna być zaakceptowana odpowiedź. faktycznie wyjaśnia DLACZEGO zamiast powtarzać mantry i stwierdzać the constructor should only be used to inject dependencies.
Stavm
1
@ yannick1976, dzięki! Sprawdź
odnośne
@flobacca, czy możesz przeformułować pytanie, trudno zrozumieć, o co pytasz
Max Koretskyi
Proszę popraw mnie jeżeli się mylę. Zrozumiałem, że drzewo komponentów jest najpierw konstruowane, a następnie zmieniane jest wykrywanie. Napisałeś najpierw, że wywoływany jest konstruktor AppComponent (wraz z rozwiązanymi zależnościami), a następnie wywoływany jest konstruktor ChildComponent (wraz z zależnościami), a następnie wywoływane są powiązania wejściowe dla AppComponent, a następnie OnInit. Ale martwię się, jeśli dodam haki cyklu życia do obu komponentów, przepływ to AppComponentConstructor - -> AppComponentOnInit - → ChildComponentConstructor - → ChildComponentOnInit Dlaczego AppComponentOnInit jest wywoływany przed ChildComponentConstructor
użytkownik2485435
1
@MaxKoretskyiakaWizard miałeś rację. Popełniłem błąd w konfiguracji aplikacji. działa zgodnie z opisem przez ciebie. angular-c7zjsx.stackblitz.io
user2485435
93

Myślę, że najlepszym przykładem byłoby korzystanie z usług. Powiedzmy, że chcę pobrać dane z mojego serwera, gdy mój komponent zostanie aktywowany. Powiedzmy, że chcę też zrobić kilka dodatkowych rzeczy do danych po pobraniu ich z serwera, może dostaję błąd i chcę je zapisać inaczej.

Dzięki konstruktorowi ngOnInit jest to naprawdę łatwe, ogranicza także liczbę warstw wywołania zwrotnego, które muszę dodać do mojej aplikacji.

Na przykład:

export class Users implements OnInit{

    user_list: Array<any>;

    constructor(private _userService: UserService){
    };

    ngOnInit(){
        this.getUsers();
    };

    getUsers(){
        this._userService.getUsersFromService().subscribe(users =>  this.user_list = users);
    };


}

z moim konstruktorem mógłbym po prostu wywołać moją _userService i zapełnić moją listę użytkowników, ale może chcę zrobić z nią dodatkowe rzeczy. Na przykład, aby upewnić się, że wszystko jest wielkimi literami, nie jestem całkowicie pewien, w jaki sposób przechodzą moje dane.

Dzięki temu korzystanie z ngOnInit jest znacznie łatwiejsze.

export class Users implements OnInit{

    user_list: Array<any>;

    constructor(private _userService: UserService){
    };

    ngOnInit(){
        this.getUsers();
    };

    getUsers(){
        this._userService.getUsersFromService().subscribe(users =>  this.user_list = users);
        this.user_list.toUpperCase();
    };


}

To sprawia, że ​​jest znacznie łatwiej zobaczyć, więc po prostu wywołuję swoją funkcję w moim komponencie, kiedy inicjuję, zamiast konieczności szukania jej gdzie indziej. Naprawdę jest to kolejne narzędzie, którego można użyć, aby ułatwić czytanie i korzystanie w przyszłości. Uważam też, że umieszczanie wywołań funkcji w konstruktorze jest naprawdę złą praktyką!

Morgan G.
źródło
Twój przykład można uprościć, jeśli ustawisz user_list na Observable. Angular2 ma potok asynchroniczny, więc nie byłoby żadnych problemów.
DarkNeuron,
@ Organ, właśnie dla mnie, aby nauczyć się tutaj małej rzeczy, dlaczego najpierw tworzysz funkcję, getUsersa następnie wstawiasz ją ngOnInit? Czy napisanie go w ngOnInit nie jest mniejszym kodem? Zastanawiam się, dlaczego ludzie robią to w ten sposób? Czy to tak, że możesz ponownie użyć kodu, jeśli chcesz? Dzięki.
Alfa Bravo,
31
Jak widać w odpowiedzi poniżej, nie ma znaczenia, czy jest w konstruktorze. To nie jest prawdziwa odpowiedź na cel.
Jimmy Kane
8
W ogóle nie rozumiem, jak to odpowiada na pytanie. Dlaczego nie mogłeś po prostu wstawić kodu constructor?
CodyBugstein
1
@ Organ, dlaczego nie możesz tego zrobićconstructor(private _userService: UserService){ this.getUsers(); };
Ashley,
82

OK, przede wszystkim ngOnInitjest częścią cyklu życia Angular , podczas gdy constructorjest częścią ES6 klasy JavaScript, więc główna różnica zaczyna się tutaj! ...

Spójrz na utworzony przeze mnie wykres, który pokazuje cykl życia Angulara.

ngOnInit vs konstruktor

W Angular2 + robimy constructorto DI(Dependency Injection)za nas, podczas gdy w Angular 1 odbywało się to poprzez wywołanie metody String i sprawdzenie, która zależność została wstrzyknięta.

Jak widać na powyższym diagramie, ngOnInitdzieje się po tym, jak konstruktor jest gotowy ngOnChnagesi zostaje zwolniony po tym, jak komponent jest dla nas gotowy. Cała inicjalizacja może nastąpić na tym etapie, prosta próbka wstrzykuje usługę i inicjuje ją przy init.

OK, ja też udostępnić przykładowy kod, aby spojrzeć, zobaczyć w jaki sposób możemy uzyskać wykorzystania ngOnIniti constructorw kodzie poniżej:

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


@Component({
 selector: 'my-app',
 template: `<h1>App is running!</h1>
  <my-app-main [data]=data></<my-app-main>`,
  styles: ['h1 { font-weight: normal; }']
})
class ExampleComponent implements OnInit {
  constructor(private router: Router) {} //Dependency injection in the constructor

  // ngOnInit, get called after Component initialised! 
  ngOnInit() {
    console.log('Component initialised!');
  }
}
Alireza
źródło
1
Dzięki. to powinna być najlepsza odpowiedź.
Don Dilanga
58

Pierwszy (konstruktor) jest powiązany z instancją klasy i nie ma nic wspólnego z Angular2. Mam na myśli, że konstruktor może być używany w dowolnej klasie. Możesz wprowadzić w nim przetwarzanie inicjujące dla nowo utworzonej instancji.

Drugi odpowiada hakowi cyklu życia komponentów Angular2:

Cytat z oficjalnej strony Angulara:

  • ngOnChanges jest wywoływany, gdy zmienia się wartość wiązania wejściowego lub wyjściowego
  • ngOnInit nazywa się po pierwszym ngOnChanges

Dlatego powinieneś użyć, ngOnInitjeśli przetwarzanie inicjujące opiera się na powiązaniach komponentu (na przykład parametry komponentu zdefiniowane za pomocą @Input), w przeciwnym razie konstruktor wystarczy ...

Thierry Templier
źródło
49

Dodam tylko jedną ważną rzecz, która została pominięta w powyższych wyjaśnieniach i wyjaśnia, kiedy MUSISZ użyć ngOnInit.

Jeśli wykonujesz jakąkolwiek manipulację DOM komponentu za pomocą np. ViewChildren , ContentChildren lub ElementRef , twoje rodzime elementy nie będą dostępne podczas fazy konstruktora.

Ponieważ jednak ngOnInitzdarza się to po utworzeniu komponentu i ngOnChangeswywołaniu funkcji check ( ), możesz uzyskać dostęp do DOM w tym momencie.

export class App implements OnInit, AfterViewInit, AfterContentInit {
  @Input() myInput: string;
  @ViewChild() myTemplate: TemplateRef<any>;
  @ContentChild(ChildComponent) myComponent: ChildComponent; 

  constructor(private elementRef: ElementRef) {
     // this.elementRef.nativeElement is undefined here
     // this.myInput is undefined here
     // this.myTemplate is undefined here
     // this.myComponent is undefine here
  }

  ngOnInit() {
     // this.elementRef.nativeElement can be used from here on
     // value of this.myInput is passed from parent scope
     // this.myTemplate and this.myComponent are still undefined
  }
  ngAfterContentInit() {
     // this.myComponent now gets projected in and can be accessed
     // this.myTemplate is still undefined
  }

  ngAfterViewInit() {
     // this.myTemplate can be used now as well
  }
}
Miroslav Jonas
źródło
3
Nie. W @ViewChildrenszczególności musisz użyć tej ngAfterViewInitmetody. Zobacz tutaj: stackoverflow.com/questions/46314734/…
AsGoodAsItGets 30.01.2019
1
Dzięki, @AsGoodAsItGets za wskazanie tego. Poprawiłem teraz odpowiedź
Miroslav Jonas,
38

Krótka i prosta odpowiedź brzmiałaby:

Constructor: constructorjest default methodprzebiegiem ( niesłyszącym ) podczas konstruowania komponentu. Gdy utworzysz an instanceklasę, ten czas również constructor(default method)zostanie wywołany. Innymi słowy, kiedy constructed or/and an instance is created constructor(default method)wywoływany jest komponent i wywoływany jest odpowiedni kod wewnątrz. Zasadniczo i ogólnie w Angular2nim służy do wstrzykiwania rzeczy, takich jak servicespodczas konstruowania komponentu do dalszego wykorzystania.

OnInit: ngOnInit to hak cyklu życia komponentu, który jest uruchamiany pierwszy po constructor(default method)inicjalizacji komponentu.

Twój konstruktor zostanie najpierw wywołany, a Oninit zostanie wywołany później po metodzie konstruktora.

boot.ts

import {Cmomponent, OnInit} from 'angular2/core';
import {ExternalService} from '../externalService';

export class app implements OnInit{
   constructor(myService:ExternalService)
   {
           this.myService=myService;
   }

   ngOnInit(){
     // this.myService.someMethod() 
   }
}

Zasoby: Hak cyklu życia

Możesz sprawdzić to małe demo, które pokazuje implementację obu rzeczy.

mikroniki
źródło
5
Myślę, że „konstruktor jest czymś, co działa lub wywołuje podczas inicjalizacji komponentu”. wprowadza w błąd. Konstruktor jest cechą klasy, a nie komponentu. Powiedziałbym, że instancja klasy staje się komponentem dopiero po wywołaniu konstruktora i zainicjowaniu Angulara.
Günter Zöchbauer
Tak zmieniło oświadczenie, które możesz sprawdzić teraz.
micronyks
1
Hmm, IMHO to wciąż ten sam „konstruktor (metoda domyślna) to coś, co działa lub jest wywoływane podczas konstruowania komponentu”. Jest wywoływany nie tylko podczas konstruowania komponentu, ale także w przypadku usług lub new MyClass()wykonywania podobnego kodu . Myślę, że mylące jest twierdzenie, że konstruktory dotyczą komponentów, dotyczą klas i inicjują instancje tych klas. Komponent jest akurat taką klasą. W przeciwnym razie uważam, że to dobra odpowiedź.
Günter Zöchbauer
2
Tak, absolutnie. Zapomniałem wspomnieć, że kiedy tworzysz obiekt klasy, również ten czas constructorbyłby wywoływany. Ale ta odpowiedź została napisana w kontekście angular2. Aby poznać najlepszą odpowiedź, musisz znać podstawy OOP. Nadal zaktualizuję odpowiedź.
micronyks
@ GünterZöchbauer, nie sądzę, że jest to poprawne stwierdzenie, które jest cechą klasy, a nie komponentu . Z perspektywy języka programowania tak, jest to poprawne. Ale mogę z powodzeniem pracować z komponentami bez żadnych haków cyklu życia. Ale nie mogę pracować z komponentem bez konstruktora, jeśli potrzebuję DI, ponieważ jest to jedyne miejsce do wstrzyknięcia. Zobacz moją odpowiedź
Max Koretskyi
20

Podobnie jak wiele innych języków, możesz inicjalizować zmienne na poziomie klasy, konstruktora lub metody. Deweloper decyduje, co jest najlepsze w ich konkretnym przypadku. Ale poniżej znajduje się lista najlepszych praktyk, jeśli chodzi o podejmowanie decyzji.

Zmienne na poziomie klasy

Zazwyczaj tutaj zadeklarujesz wszystkie swoje zmienne, które zostaną wykorzystane w pozostałej części komponentu. Możesz je zainicjować, jeśli wartość nie zależy od niczego innego, lub użyć słowa kluczowego const, aby utworzyć stałe, jeśli się nie zmienią.

export class TestClass{
    let varA: string = "hello";
}

Konstruktor

Zwykle najlepszą praktyką jest nie robienie niczego w konstruktorze i używanie go tylko dla klas, które zostaną wstrzyknięte. Przez większość czasu twój konstruktor powinien wyglądać tak:

   constructor(private http: Http, private customService: CustomService) {}

spowoduje to automatyczne utworzenie zmiennych na poziomie klasy, dzięki czemu będziesz mieć dostęp do customService.myMethod() bez konieczności robienia tego ręcznie.

NgOnInit

NgOnit to hak cyklu życia zapewniany przez platformę Angular 2. Komponent musi zostać wdrożony OnInit, aby go użyć. Ten hak cyklu życia jest wywoływany po wywołaniu konstruktora i zainicjowaniu wszystkich zmiennych. Większość inicjalizacji powinna znaleźć się tutaj. Będziesz mieć pewność, że Angular poprawnie zainicjował twój komponent i możesz zacząć robić logikę, jakiej potrzebujeszOnInit porównaniu do robienia rzeczy, gdy twój komponent nie załaduje się poprawnie.

Oto obraz przedstawiający kolejność wywoływania:

wprowadź opis zdjęcia tutaj

https://angular.io/docs/ts/latest/guide/lifecycle-hooks.html

TLDR

Jeśli używasz frameworka Angular 2 i chcesz wchodzić w interakcje z niektórymi zdarzeniami cyklu życia, użyj metod dostarczonych przez frameworkę, aby uniknąć problemów.

Eduardo Dennis
źródło
19

Aby to przetestować, napisałem ten kod, korzystając z samouczka NativeScript :

user.ts

export class User {
    email: string;
    password: string;
    lastLogin: Date;

    constructor(msg:string) {        
        this.email = "";
        this.password = "";
        this.lastLogin = new Date();
        console.log("*** User class constructor " + msg + " ***");
    }

    Login() {
    }
}

login.component.ts

import {Component} from "@angular/core";
import {User} from "./../../shared/user/user"

@Component({
  selector: "login-component",
  templateUrl: "pages/login/login.html",
  styleUrls: ["pages/login/login-common.css", "pages/login/login.css"]
})
export class LoginComponent {

  user: User = new User("property");  // ONE
  isLoggingIn:boolean;

  constructor() {    
    this.user = new User("constructor");   // TWO
    console.log("*** Login Component Constructor ***");
  }

  ngOnInit() {
    this.user = new User("ngOnInit");   // THREE
    this.user.Login();
    this.isLoggingIn = true;
    console.log("*** Login Component ngOnInit ***");
  }

  submit() {
    alert("You’re using: " + this.user.email + " " + this.user.lastLogin);
  }

  toggleDisplay() {
    this.isLoggingIn = !this.isLoggingIn;
  }

}

Wyjście konsoli

JS: *** User class constructor property ***  
JS: *** User class constructor constructor ***  
JS: *** Login Component Constructor ***  
JS: *** User class constructor ngOnInit ***  
JS: *** Login Component ngOnInit ***  
abbaf33f
źródło
18

Główną różnicą między konstruktorem a ngOnInitjest to, że ngOnInitjest to hak cyklu życia i działa za konstruktorem. Interpolowany szablon komponentu i wejściowe wartości początkowe nie są dostępne w konstruktorze, ale są dostępne w ngOnInit.

Praktyczną różnicą jest to, w jaki sposób ngOnInitwpływa na strukturę kodu. Większość kodu inicjalizacji można przenieść do ngOnInit- o ile nie stwarza to warunków wyścigu .

Konstruktor antipattern

Znaczna ilość kodu inicjującego powoduje, że metoda konstruktora jest trudna do rozszerzenia, odczytu i przetestowania.

Zwykłym przepisem oddzielającym logikę inicjalizacji od konstruktora klasy jest przeniesienie jej do innej metody, takiej jak init:

class Some {
  constructor() {
    this.init();
  }

  init() {...}
}

ngOnInit może służyć do tego celu w komponentach i dyrektywach:

constructor(
  public foo: Foo,
  /* verbose list of dependencies */
) {
  // time-sensitive initialization code
  this.bar = foo.getBar();
}

ngOnInit() {
  // rest of initialization code
}

Zastrzyk zależności

Podstawową rolą konstruktorów klas w Angular jest wstrzykiwanie zależności. Konstruktory są również używane do adnotacji DI w TypeScript. Prawie wszystkie zależności są przypisane jako właściwości do instancji klasy.

Przeciętny konstruktor komponentu / dyrektywy jest już wystarczająco duży, ponieważ może mieć sygnaturę wielowierszową z powodu zależności, wprowadzając niepotrzebną logikę inicjalizacji do ciała konstruktora.

Asynchroniczna inicjalizacja

Konstruktor inicjacji asynchronicznej często może być uważany za anty-wzorzec i ma zapach, ponieważ tworzenie instancji klasy kończy się przed wykonaniem procedury asynchronicznej, co może tworzyć warunki wyścigu. Jeśli tak nie jest, ngOnInita inne haki cyklu życia są lepszymi miejscami do tego, szczególnie dlatego, że mogą skorzystać ze asyncskładni:

constructor(
  public foo: Foo,
  public errorHandler: ErrorHandler
) {}

async ngOnInit() {
  try {
    await this.foo.getBar();
    await this.foo.getBazThatDependsOnBar();
  } catch (err) {
    this.errorHandler.handleError(err);
  }
}

Jeśli istnieją warunki wyścigu (w tym taki, że komponent nie powinien pojawić się po błędzie inicjalizacji), asynchroniczna procedura inicjalizacji powinna odbyć się przed utworzeniem instancji komponentu i zostać przeniesiona do komponentu nadrzędnego, osłony routera itp.

Testów jednostkowych

ngOnInitjest bardziej elastyczny niż konstruktor i zapewnia pewne korzyści dla testów jednostkowych, które zostały szczegółowo wyjaśnione w tej odpowiedzi .

Biorąc pod uwagę, że ngOnInitnie jest on wywoływany automatycznie podczas kompilacji komponentów w testach jednostkowych, wywoływane metody ngOnInitmożna śledzić lub wyśmiewać po utworzeniu wystąpienia komponentu.

W wyjątkowych przypadkach ngOnInitmożna go całkowicie zatrzeć, aby zapewnić izolację dla innych jednostek składowych (na przykład logiki niektórych szablonów).

Dziedzictwo

Klasy potomne mogą jedynie rozszerzać konstruktory, a nie zastępować je.

Ponieważ thisnie można się do niego wcześniej odwoływać super(), nakłada to ograniczenia na pierwszeństwo inicjalizacji.

Biorąc pod uwagę, że komponent lub dyrektywa Angular używa ngOnInitdo logiki inicjalizacji niewrażliwej na czas, klasy potomne mogą wybrać, czy super.ngOnInit()mają być wywoływane i kiedy:

ngOnInit() {
  this.someMethod();
  super.ngOnInit();
}

Byłoby to niemożliwe do wdrożenia za pomocą samego konstruktora.

Estus Flask
źródło
12

Powyższe odpowiedzi tak naprawdę nie odpowiadają na ten aspekt pierwotnego pytania: Co to jest hak cyklu życia? Trochę czasu zajęło mi zrozumienie, co to znaczy, dopóki nie pomyślałem o tym w ten sposób.

1) Powiedz, że twój element to człowiek. Ludzie mają życie, które obejmuje wiele etapów życia, a potem wygasamy.

2) Nasz ludzki komponent może mieć następujący scenariusz cyklu życia: urodzony, dziecko, szkoła klasowa, młody dorosły, dorosły w średnim wieku, starszy dorosły, martwy, unieszkodliwiony.

3) Powiedz, że chcesz mieć funkcję tworzenia dzieci. Aby uniknąć komplikacji i raczej humoru, chcesz, aby twoja funkcja była wywoływana tylko podczas etapu Młodego Dorosłego w ludzkim życiu. Opracowujesz komponent, który jest aktywny tylko wtedy, gdy komponent macierzysty znajduje się w fazie Młodego Dorosłego. Haki pomagają ci to zrobić, sygnalizując ten etap życia i pozwalając na to, aby twój komponent działał na nim.

Zabawne rzeczy. Jeśli pozwolisz swojej wyobraźni zakodować coś takiego, komplikuje się i staje się zabawna.

Preston
źródło
7

Konstruktor jest to metoda w JavaScript i jest uważana za cechę klasy w ES6 .Przy klasa jest tworzony natychmiast uruchamia konstruktora czy jest on stosowany w ramach kątowe lub not.So jest nazywany silnikiem JavaScript i kątowa nie ma kontrolować to.

import {Component} from '@angular/core';
@Component({})
class CONSTRUCTORTEST {

//This is called by Javascript not the Angular.
     constructor(){
        console.log("view constructor initialised");
     }
}

Poniżej znajduje się instancja klasy „ConstructorTest”, która wewnętrznie wywołuje konstruktor (wszystko to dzieje się w JavaScript (es6) bez Angulara).

new CONSTRUCTORTEST();

Dlatego w Angular znajduje się hak cyklu życia ngOnInit .ngOnInit renderuje, gdy Angular zakończy inicjalizację komponentu.

import {Component} from '@angular/core';
@Component({})
class NGONINITTEST implements onInit{
   constructor(){}
   //ngOnInit calls by Angular
   ngOnInit(){
     console.log("Testing ngOnInit");
   }
}

Najpierw tworzymy instancję klasy, jak poniżej, co dzieje się z natychmiastowymi uruchomieniami metody konstruktora.

let instance = new NGONINITTEST();

ngOnInit jest wywoływany przez Angular, gdy jest to konieczne, jak poniżej:

instance.ngOnInit();

Ale możesz zapytać, dlaczego używamy konstruktora w Angular?

Odpowiedzią są zastrzyki zależności . Jak wspomniano wcześniej, konstruktor wywołuje silnik JavaScript natychmiast po utworzeniu instancji klasy (przed wywołaniem ngOnInit przez Angular), więc maszynopis pomaga nam uzyskać typ zależności zdefiniowanych w konstruktorze i na koniec informuje Kątowe, jakiego rodzaju zależności chcemy użyć w tym konkretnym komponencie.

Negin
źródło
7

Dwie rzeczy do zaobserwowania tutaj:

  1. Konstruktor jest wywoływany za każdym razem, gdy tworzony jest obiekt tej klasy.
  2. ngOnInit wywoływane po utworzeniu komponentu.

Oba mają różną użyteczność.

UniCoder
źródło
5

Konstruktor () jest domyślną metodą w cyklu życia komponentu i służy do wstrzykiwania zależności. Konstruktor to funkcja maszynopisu.

ngOnInit () jest wywoływany po konstruktorze, a ngOnInit jest wywoływany po pierwszych ngOnChanges.

to znaczy:

Constructor () -->ngOnChanges ()--> ngOnInit ()

jak wspomniano powyżej, ngOnChanges()wywoływane jest, gdy zmienia się wartość wiązania wejściowego lub wyjściowego.

Shajin Chandran
źródło
4

Obie metody mają różne cele / obowiązki. Zadaniem konstruktora (który jest funkcją obsługiwaną przez język) jest upewnienie się, że niezmiennik reprezentacji zachowuje. Podano inaczej, aby upewnić się, że instancja jest poprawna, podając poprawne wartości członkom. To programista decyduje, co oznacza „poprawne”.

Zadaniem metody onInit () (która jest pojęciem kątowym) jest umożliwienie wywoływania metod na poprawnym obiekcie (niezmiennej reprezentacji). Każda metoda powinna z kolei upewnić się, że niezmiennik reprezentacji zachowuje się po zakończeniu metody.

Do tworzenia „poprawnych” obiektów należy używać konstruktora, metoda onInit daje możliwość wywoływania wywołań metod w dobrze zdefiniowanej instancji.

Bruno Ranschaert
źródło
4

Konstruktor: Metoda konstruktora w klasie ES6 (lub w tym przypadku TypeScript) jest cechą samej klasy, a nie cechą Angular. Nie jest pod kontrolą Angulara, gdy wywoływany jest konstruktor, co oznacza, że ​​nie jest to odpowiedni haczyk, który informuje, kiedy Angular skończył inicjować komponent. Silnik JavaScript wywołuje konstruktor, a nie bezpośrednio Angular. Dlatego właśnie utworzono hak cyklu życia ngOnInit (i $ onInit w AngularJS). Mając to na uwadze, istnieje odpowiedni scenariusz użycia konstruktora. W tym momencie chcemy zastosować wstrzykiwanie zależności - zasadniczo do „zależności” między komponentami.

Ponieważ konstruktor jest inicjowany przez silnik JavaScript, a TypeScript pozwala nam powiedzieć Angularowi, jakie zależności musimy zmapować względem konkretnej właściwości.

ngOnInit jest po to, aby dać nam sygnał, że Angular zakończył inicjalizację komponentu.

Ta faza obejmuje pierwsze przejście podczas Wykrywania Zmian względem właściwości, które możemy powiązać z samym komponentem - na przykład za pomocą dekoratora @Input ().

Z tego powodu właściwości @Input () są dostępne w ngOnInit, jednak z definicji są niezdefiniowane w konstruktorze

Vishal Gulati
źródło
2

Konstruktor jest pierwszy i zdarza się czasem, gdy dane @input są zerowe! więc używamy Constructor do deklarowania usług, a ngOnInit dzieje się później. Przykład dla kontrahenta:

 constructor(translate: TranslateService, private oauthService: OAuthService) {
    translate.setDefaultLang('En');
        translate.use('En');}

Przykład dla onInit:

ngOnInit() {
    this.items = [
      { label: 'A', icon: 'fa fa-home', routerLink: ['/'] },
      { label: 'B', icon: 'fa fa-home', routerLink: ['/'] }]
}

Myślę, że onInit jest podobny do InitialComponents () w winForm.

użytkownik1012506
źródło
1

W cyklicznych cyklach życia

1) Kątowy wtryskiwacz wykrywa parametry konstruktora i tworzy instancję klasy.

2) Następny cykl życia połączenia kątowego

Haczyki kątowe cyklu życia

ngOnChanges -> Wywołanie w powiązaniu parametrów dyrektywy.

ngOnInit -> Rozpocznij renderowanie kątowe ...

Wywołaj inną metodę ze stanem kątowego cyklu życia.

Muzułmanin Shahsavan
źródło
1

constructorJest wywoływana, gdy kątowe „instanciates / konstrukty” komponent. ngOnInitMetoda jest hak, który stanowi część inicjalizacji cyklu życia komponentów. Dobrą praktyką jest używanie go tylko do wstrzykiwania usługi :

constructor(private 
    service1: Service1,
    service2: Service2
){};

Nawet jeśli jest to możliwe, nie powinieneś wykonywać „pracy” w środku. Jeśli chcesz uruchomić jakąś akcję, która musi nastąpić przy inicjalizacji komponentu, użyj ngOnInit:

ngOnInit(){
    service1.someWork();
};

Co więcej, działania obejmujące właściwości wejściowe pochodzące od komponentu nadrzędnego nie mogą być wykonane w kontrolerze. Powinny być umieszczone w ngOnInitmetodzie lub innym haku. To samo dotyczy elementu związanego z widokiem (DOM), na przykład elementów viewchild :

@Input itemFromParent: string;
@ViewChild('childView') childView;

constructor(){
    console.log(itemFromParent); // KO
    // childView is undefined here
};

ngOnInit(){
    console.log(itemFromParent); // OK
    // childView is undefined here, you can manipulate here
};
veben
źródło
0

constructor() służy do wstrzykiwania zależności.

ngOnInit(), ngOnChanges()I ngOnDestroy()itd. Są metody cyklu życia. ngOnChanges()będzie wywoływany jako pierwszy, wcześniej ngOnInit(), gdy zmieni się wartość powiązanej właściwości, NIE zostanie on wywołany, jeśli nie nastąpi zmiana. ngOnDestroy()jest wywoływany po usunięciu komponentu. Aby go użyć, OnDestroymusi być implementedytowany przez klasę.

xameeramir
źródło
1
zgadzam się, to jest krótkie i jasne. Na przykład, konstruktor () służy do dodawania obiektów usług, ngOnInit () służy do manipulowania komponentami za pomocą niezbędnych wywołań funkcji usług.
Steve
0

Znalazłem odpowiedź i próbowałem przetłumaczyć ją na angielski: To pytanie wciąż się pojawiało, nawet w wywiadach technicznych. W rzeczywistości istnieje duże podobieństwo między nimi, ale są też pewne różnice.

  • Konstruktor jest częścią ECMAScript. Z drugiej strony ngOnInit () jest pojęciem kątowym.

  • Możemy wywoływać konstruktory we wszystkich klasach, nawet jeśli nie używamy Angulara

  • LifeCycle: Konstruktor jest wywoływany przed ngOnInt ()

  • W konstruktorze nie możemy wywoływać elementów HTML. Jednak w ngOnInit () możemy.

  • Zasadniczo wywołania usług w ngOnInit (), a nie w konstruktorze

    Źródło: http://www.angular-tuto.com/Angular/Component#Diff

doudou
źródło
0

Konstruktor

Funkcja konstruktora jest dostarczana z każdą klasą, konstruktory nie są specyficzne dla Angular, ale są koncepcjami pochodzącymi z projektów obiektowych. Konstruktor tworzy instancję klasy komponentu.

OnInit

Ta ngOnInitfunkcja jest jedną z metod cyklu życia komponentu kątowego. Metody cyklu życia (lub haki) w komponentach Angular pozwalają na uruchomienie fragmentu kodu na różnych etapach życia komponentu. W przeciwieństwie do metody konstruktora metoda ngOnInitpochodzi z interfejsu Angular ( OnInit), który komponent musi zaimplementować, aby użyć tej metody. ngOnInitMetoda nazywa się krótko po składnik jest tworzony.

DeC
źródło
0

Konstruktor jest wykonywany podczas tworzenia instancji klasy. Nie ma to nic wspólnego z kanciastością. Jest to funkcja Javascript, a Angular nie ma nad nią kontroli

NgOnInit jest specyficzne dla Angulara i jest wywoływane, gdy Angular zainicjuje komponent ze wszystkimi jego właściwościami wejściowymi

Właściwości @Input są dostępne pod hakiem cyklu życia ngOnInit. Pomoże Ci to wykonać pewne czynności inicjalizacyjne, takie jak pobieranie danych z serwera zaplecza itp. Do wyświetlenia w widoku

@Input właściwości są wyświetlane jako niezdefiniowane wewnątrz konstruktora

dasunse
źródło
-1

Konstruktor to funkcja wykonywana, gdy budowany jest komponent (lub inna klasa).

ngOnInit jest funkcją należącą do grup metod cyklu życia komponentu i są one wykonywane w innym momencie naszego komponentu (stąd nazwa cyklu życia). Oto ich lista:

wprowadź opis zdjęcia tutaj Konstruktor zostanie wykonany przed jakąkolwiek funkcją cyklu życia.

Przemek Struciński
źródło