Unterschied zwischen Konstruktor und ngOnInit

Antworten:

1110

Dies Constructorist eine Standardmethode der Klasse, die ausgeführt wird, wenn die Klasse instanziiert wird, und die ordnungsgemäße Initialisierung der Felder in der Klasse und ihren Unterklassen sicherstellt. Angular oder besser Dependency Injector (DI) analysiert die Konstruktorparameter und new MyClass()versucht beim Erstellen einer neuen Instanz durch Aufrufen , Anbieter zu finden, die den Typen der Konstruktorparameter entsprechen, löst sie auf und übergibt sie wie folgt an den Konstruktor

new MyClass(someArg);

ngOnInit ist ein Lebenszyklus-Hook, der von Angular aufgerufen wird, um anzuzeigen, dass Angular die Komponente erstellt hat.

Wir müssen so importieren, OnInitum es zu verwenden (die tatsächliche Implementierung OnInitist nicht obligatorisch, wird aber als gute Praxis angesehen):

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

Um make von der Methode zu verwenden OnInit, müssen wir die Klasse folgendermaßen implementieren:

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

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

Implementieren Sie diese Schnittstelle, um eine benutzerdefinierte Initialisierungslogik auszuführen, nachdem die datengebundenen Eigenschaften Ihrer Direktive initialisiert wurden. ngOnInit wird direkt aufgerufen, nachdem die datengebundenen Eigenschaften der Direktive zum ersten Mal überprüft wurden und bevor eines ihrer untergeordneten Elemente überprüft wurde. Es wird nur einmal aufgerufen, wenn die Direktive instanziiert wird.

Meistens verwenden wir ngOnInitfür die gesamte Initialisierung / Deklaration und vermeiden, dass Dinge im Konstruktor funktionieren. Der Konstruktor sollte nur zum Initialisieren von Klassenmitgliedern verwendet werden, aber keine tatsächliche "Arbeit" ausführen.

Sie sollten also constructor()Dependency Injection einrichten und nicht viel anderes. ngOnInit () ist der bessere Ort zum "Starten" - hier werden die Bindungen der Komponenten aufgelöst.

Weitere Informationen finden Sie hier:

Pardeep Jain
quelle
62
Genau, die meisten (oder sogar alle) klassenbasierten Sprachen haben Konstruktoren, um eine ordnungsgemäße Initialisierungsreihenfolge sicherzustellen, insbesondere von Klassen, die andere Klassen erweitern, in denen einige recht schwierige Probleme auftreten können, wie z. B. Abschlussfelder (ich weiß nicht, ob TS sie hat) und ähnliches. Konstruktoren sind nicht mit Angular2 verwandt, sondern eine TypeScript-Funktion. Lifecycle-Hooks werden von Angular aufgerufen, nachdem eine Initialisierung stattgefunden hat oder wenn ein Ereignis eingetreten ist, damit die Komponente auf bestimmte Situationen reagieren kann und die Möglichkeit hat, einige Aufgaben zu angemessenen Zeiten auszuführen.
Günter Zöchbauer
12
In angular.io/docs/ts/latest/guide/server-communication.html gibt es ein Blockzitat , das dies ebenfalls erklärt: "Komponenten sind einfacher zu testen und zu debuggen, wenn ihre Konstruktoren einfach sind und alle echte Arbeit (insbesondere das Aufrufen von a Remote-Server) wird in einer separaten Methode behandelt. " - In diesem Fall ist diese Methode ngOnInit ()
yoonjesung
3
ist ein Lebenszyklus-Hook, der von Angular2 aufgerufen wird, um anzuzeigen, dass Angular die Komponente erstellt hat. - das ist nicht genau das. Es signalisiert, dass die Bindungen initialisiert wurden. Die Komponente wurde früher erstellt. Siehe meine Antwort
Max Koretskyi
22
Wie bei allen "Best Practices" halte ich es für eine gute Idee, auch zu erklären, warum Sie im Konstruktor keine "Arbeit" ausführen sollten. Dieser Artikel des Angular-Teamleiters ist dicht, kann aber hilfreich sein: misko.hevery.com/code-reviewers-guide/… Außerdem sollten den Beschwörungsformeln, die für die Implementierung von OnInit erforderlich sind (dies ist leicht zu finden), weniger Bedeutung beigemessen werden die kritische Tatsache, dass Datenbindungen im Konstruktor nicht verfügbar sind.
Reikim
2
Wenn der strikte Modus in einer tsconfig.jsonDatei wie " true" wahr ist "strict": true, müssen Sie die Klassenmitglieder constructorin " ngOnitlike" initialisieren FormGroup.
Rohit Sharma
172

Der Artikel Der wesentliche Unterschied zwischen Konstruktor und ngOnInit in Angular untersucht den Unterschied aus mehreren Perspektiven. Diese Antwort enthält die wichtigste Erklärung für den Unterschied im Zusammenhang mit dem Initialisierungsprozess der Komponenten, die auch die unterschiedlichen Verwendungszwecke zeigt.

Der Angular Bootstrap-Prozess besteht aus zwei Hauptstufen:

  • Komponentenbaum erstellen
  • laufende Änderungserkennung

Der Konstruktor der Komponente wird aufgerufen, wenn Angular den Komponentenbaum erstellt. Alle Lifecycle-Hooks werden als Teil der laufenden Änderungserkennung aufgerufen.

Wenn Angular einen Komponentenbaum erstellt, ist der Root-Modul-Injektor bereits konfiguriert, sodass Sie alle globalen Abhängigkeiten einfügen können. Wenn Angular eine untergeordnete Komponentenklasse instanziiert, ist der Injektor für die übergeordnete Komponente bereits eingerichtet, sodass Sie auf der übergeordneten Komponente definierte Anbieter einschließlich der übergeordneten Komponente selbst injizieren können. Komponentenkonstruktoren sind die einzige Methode, die im Kontext des Injektors aufgerufen wird. Wenn Sie also eine Abhängigkeit benötigen, ist dies der einzige Ort, an dem diese Abhängigkeiten abgerufen werden können.

Wenn Angular mit der Änderungserkennung beginnt, wird der Komponentenbaum erstellt und die Konstruktoren für alle Komponenten im Baum wurden aufgerufen. Außerdem werden die Vorlagenknoten jeder Komponente zum DOM hinzugefügt. Der @InputKommunikationsmechanismus wird während der Änderungserkennung verarbeitet, sodass Sie nicht erwarten können, dass die Eigenschaften im Konstruktor verfügbar sind. Es wird am nach verfügbar seinngOnInit .

Sehen wir uns ein kurzes Beispiel an. Angenommen, Sie haben die folgende Vorlage:

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

Angular startet also das Bootstrapping der Anwendung. Wie gesagt, es werden zuerst Klassen für jede Komponente erstellt. Also nennt es MyAppComponentKonstruktor. Außerdem wird ein DOM-Knoten erstellt, der das Hostelement der my-appKomponente ist. Anschließend wird ein Hostelement für den Konstruktor child-compund aufrufend erstellt ChildComponent. In dieser Phase geht es nicht wirklich um die iEingabebindung und etwaige Lebenszyklus-Hooks. Wenn dieser Vorgang abgeschlossen ist, erhält Angular den folgenden Baum von Komponentenansichten:

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

Erst dann wird die Änderungserkennung ausgeführt und die Bindungen für die my-appund ngOnInitdie MyAppComponent-Klasse aktualisiert. Anschließend werden die Bindungen für die child-compund ngOnInitdie ChildComponent-Klasse aktualisiert .

Sie können Ihre Initialisierungslogik entweder im Konstruktor oder ngOnInitje nach Bedarf ausführen. Beispiel: Der Artikel Hier erfahren Sie, wie Sie ViewContainerRef abrufen, bevor die @ ViewChild-Abfrage ausgewertet wird. Sie zeigt, welche Art von Initialisierungslogik im Konstruktor ausgeführt werden muss.

Hier sind einige Artikel, die Ihnen helfen, das Thema besser zu verstehen:

Max Koretskyi
quelle
33
Dies sollte die akzeptierte Antwort sein. es erklärt tatsächlich das WARUM, anstatt Mantras zu wiederholen und zu sagen the constructor should only be used to inject dependencies.
Stavm
1
@ yannick1976, danke! Schauen Sie sich die Artikel an, auf die verwiesen wird
Max Koretskyi
@ Flobacca, können Sie bitte die Frage umformulieren, es ist schwer zu verstehen, was Sie fragen
Max Koretskyi
Bitte korrigieren Sie mich, wenn ich falsch liege. Ich habe verstanden, dass der Komponentenbaum zuerst erstellt wird und dann den Erkennungsprozess ändert. Sie haben geschrieben, dass zuerst der AppComponent-Konstruktor aufgerufen wird (zusammen mit aufgelösten Abhängigkeiten), dann der ChildComponent-Konstruktor aufgerufen wird (zusammen mit Abhängigkeiten), dann Eingabebindungen für AppComponent aufgerufen werden und dann OnInit aufgerufen wird. Aber ich mache mir Sorgen, wenn ich beiden Komponenten Lebenszyklus-Hooks hinzufüge, lautet der Ablauf AppComponentConstructor - -> AppComponentOnInit - → ChildComponentConstructor - → ChildComponentOnInit Warum AppComponentOnInit vor ChildComponentConstructor aufgerufen wird
user2485435
1
@ MaxKoretskyiakaWizard Sie hatten Recht. Ich habe einen Fehler in meinem Anwendungssetup gemacht. es funktioniert wie von dir beschrieben. angle-c7zjsx.stackblitz.io
user2485435
94

Ich denke, das beste Beispiel wäre die Nutzung von Diensten. Angenommen, ich möchte Daten von meinem Server abrufen, wenn meine Komponente aktiviert wird. Angenommen, ich möchte einige zusätzliche Dinge an den Daten vornehmen, nachdem ich sie vom Server erhalten habe. Vielleicht erhalte ich eine Fehlermeldung und möchte sie anders protokollieren.

Mit ngOnInit ist es sehr einfach, einen Konstruktor zu verwenden. Außerdem wird die Anzahl der Rückrufebenen begrenzt, die ich meiner Anwendung hinzufügen muss.

Zum Beispiel:

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);
    };


}

Mit meinem Konstruktor könnte ich einfach meinen _userService aufrufen und meine Benutzerliste auffüllen, aber vielleicht möchte ich ein paar zusätzliche Dinge damit machen. Um sicherzustellen, dass alles in Großbuchstaben geschrieben ist, bin ich mir nicht ganz sicher, wie meine Daten durchkommen.

Dies erleichtert die Verwendung von ngOnInit erheblich.

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();
    };


}

Es macht es viel einfacher zu sehen, und so rufe ich meine Funktion einfach innerhalb meiner Komponente auf, wenn ich initialisiere, anstatt irgendwo anders danach suchen zu müssen. Es ist wirklich nur ein weiteres Tool, mit dem Sie das Lesen und Verwenden in Zukunft vereinfachen können. Außerdem finde ich es wirklich schlecht, Funktionsaufrufe in einen Konstruktor zu setzen!

Morgan G.
quelle
Ihr Beispiel könnte vereinfacht werden, wenn Sie nur user_list auf Observable setzen. Angular2 hat die asynchrone Pipe, sodass es dort keine Probleme geben würde.
DarkNeuron
@Morgan, nur damit ich hier etwas lernen kann, warum erstellen Sie zuerst eine Funktion getUsersund fügen sie dann ein ngOnInit? Ist es nicht weniger Code, ihn einfach in ngOnInit zu schreiben? Ich frage mich nur, warum die Leute das so machen. Ist es so, dass Sie den Code wiederverwenden können, wenn Sie es auch wollten? Vielen Dank.
Alfa Bravo
31
Wie in der Antwort unten zu sehen ist, macht dies keinen Unterschied, ob es sich um den Konstruktor handelt. Dies ist keine echte Antwort auf den Zweck.
Jimmy Kane
8
Ich sehe nicht, wie dies die Frage überhaupt beantwortet. Warum konnten Sie den Code nicht einfach in das Feld einfügen constructor?
CodyBugstein
1
@ Morgan, warum kannst du nicht einfach tunconstructor(private _userService: UserService){ this.getUsers(); };
Ashley
82

OK, in erster Linie ngOnInitist Teil des Angular - Lebenszyklus , während ein constructorTeil ist ES6 JavaScript - Klasse, so dass der große Unterschied von hier beginnt! ...

Schauen Sie sich das folgende Diagramm an, das den Lebenszyklus von Angular zeigt.

ngOnInit vs Konstruktor

In Angular2 + erledigen wir constructordas DI(Dependency Injection)für uns, während es in Angular 1 durch Aufrufen der String-Methode und Überprüfen der eingefügten Abhängigkeit geschehen ist.

Wie Sie im obigen Diagramm sehen, ngOnInitgeschieht dies, nachdem der Konstruktor bereit ist, und wird ngOnChnagesausgelöst, nachdem die Komponente für uns bereit ist. Alle Initialisierungen können in dieser Phase erfolgen. Ein einfaches Beispiel injiziert einen Dienst und initialisiert ihn bei init.

OK, ich teile auch einen Beispielcode, damit Sie sehen können, wie wir ihn verwenden, ngOnInitund constructorim folgenden Code:

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
quelle
1
Vielen Dank. Dies sollte die beste Antwort sein.
Don Dilanga
58

Der erste (Konstruktor) bezieht sich auf die Klasseninstanziierung und hat nichts mit Angular2 zu tun. Ich meine, ein Konstruktor kann für jede Klasse verwendet werden. Sie können eine Initialisierungsverarbeitung für die neu erstellte Instanz eingeben.

Der zweite entspricht einem Lebenszyklus-Hook von Angular2-Komponenten:

Zitiert von der offiziellen Website von Angular:

  • ngOnChanges wird aufgerufen, wenn sich ein Eingabe- oder Ausgabebindungswert ändert
  • ngOnInit wird nach dem ersten aufgerufen ngOnChanges

Sie sollten also verwenden, ngOnInitwenn die Initialisierungsverarbeitung auf Bindungen der Komponente beruht (z. B. mit definierte Komponentenparameter @Input), andernfalls würde der Konstruktor ausreichen ...

Thierry Templier
quelle
49

Ich werde nur eine wichtige Sache hinzufügen , die in den obigen Ausführungen und erklärt wurde übersprungen , wenn Sie MÜSSEN verwenden ngOnInit.

Wenn Sie das DOM der Komponente über ViewChildren , ContentChildren oder ElementRef bearbeiten , sind Ihre nativen Elemente während der Konstruktorphase nicht verfügbar.

Da ngOnInitdies jedoch geschieht, nachdem die Komponente erstellt und die Prüfungen ( ngOnChanges) aufgerufen wurden, können Sie an dieser Stelle auf das DOM zugreifen.

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
quelle
3
Nee. Für @ViewChildreninsbesondere, müssen Sie die verwenden ngAfterViewInitMethode. Siehe hier: stackoverflow.com/questions/46314734/…
AsGoodAsItGets
1
Vielen Dank, @AsGoodAsItGets, dass Sie darauf hingewiesen haben. Ich habe jetzt die Antwort verbessert
Miroslav Jonas
38

Kurze und einfache Antwort wäre:

Constructor: constructorist ein default methodLauf ( von taub ), wenn eine Komponente erstellt wird. Wenn Sie an instanceeine Klasse erstellen , wird diese Zeit auch constructor(default method)aufgerufen. Mit anderen Worten, wenn eine Komponente constructed or/and an instance is created constructor(default method)aufgerufen wird und der darin geschriebene relevante Code aufgerufen wird. Grundsätzlich und allgemein Angular2darin verwendet, um Dinge zu injizieren, wie serviceswenn Komponente für die weitere Verwendung konstruiert wird.

OnInit: ngOnInit ist der Lebenszyklus-Hook der Komponente, der zuerst danach ausgeführt wird constructor(default method) wenn die Komponente initialisiert wird.

Ihr Konstruktor wird also zuerst aufgerufen und Oninit wird später nach der Konstruktormethode aufgerufen.

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() 
   }
}

Ressourcen: LifeCycle-Hook

Sie können diese kleine Demo überprüfen, die die Implementierung beider Dinge zeigt.

Mikronyken
quelle
5
Ich denke, "Konstruktor ist etwas, das ausgeführt oder aufgerufen wird, wenn die Komponente initialisiert wird." ist irreführend. Der Konstruktor ist ein Merkmal der Klasse, nicht der Komponente. Ich würde sagen, die Instanz der Klasse wird erst zu einer Komponente, nachdem der Konstruktor aufgerufen und Angular seine Initialisierung durchgeführt hat.
Günter Zöchbauer
Ja, die Anweisung, die Sie jetzt überprüfen können, wurde geändert.
Mikronyken
1
Hmm, meiner Meinung nach ist es immer noch derselbe "Konstruktor (Standardmethode) wird ausgeführt oder aufgerufen, wenn eine Komponente erstellt wird." Es wird nicht nur aufgerufen, wenn eine Komponente erstellt wird, sondern auch für Dienste oder wenn Code wie new MyClass()ausgeführt wird. Ich finde es irreführend zu sagen, dass es bei Konstruktoren um Komponenten geht, um Klassen und um das Initialisieren von Instanzen dieser Klassen. Eine Komponente ist zufällig eine solche Klasse. Ansonsten denke ich, dass es eine gute Antwort ist.
Günter Zöchbauer
2
Ja absolut. Ich habe vergessen zu erwähnen, dass beim Erstellen eines Objekts einer Klasse auch diese Zeit constructoraufgerufen wird. Diese Antwort wurde jedoch im Winkel2-Kontext geschrieben. Um die beste Antwort zu erhalten, müssen Sie die Grundlagen der OOP kennen. Trotzdem werde ich die Antwort aktualisieren.
Mikronyken
@ GünterZöchbauer, ich denke nicht, dass es eine korrekte Behauptung ist, die ein Merkmal der Klasse ist, nicht der Komponente . Aus Sicht der Programmiersprache ist dies richtig. Aber ich kann erfolgreich mit Komponenten ohne Lifecycle-Hooks arbeiten. Aber ich kann nicht mit einer Komponente ohne Konstruktor arbeiten, wenn ich DI benötige, da dies der einzige injizierbare Ort ist. Siehe meine Antwort
Max Koretskyi
20

Wie in vielen anderen Sprachen können Sie Variablen auf Klassenebene, im Konstruktor oder in einer Methode initialisieren. Es ist Sache des Entwicklers, zu entscheiden, was in seinem speziellen Fall am besten ist. Im Folgenden finden Sie eine Liste der Best Practices für die Entscheidung.

Variablen auf Klassenebene

Normalerweise deklarieren Sie hier alle Ihre Variablen, die im Rest Ihrer Komponente verwendet werden. Sie können sie initialisieren, wenn der Wert von nichts anderem abhängt, oder das Schlüsselwort const verwenden, um Konstanten zu erstellen, wenn sie sich nicht ändern.

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

Konstrukteur

Normalerweise empfiehlt es sich, im Konstruktor nichts zu tun und es nur für Klassen zu verwenden, die injiziert werden. Meistens sollte Ihr Konstruktor so aussehen:

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

Dadurch werden automatisch die Variablen auf Klassenebene erstellt, sodass Sie Zugriff darauf haben, customService.myMethod()ohne dies manuell tun zu müssen.

NgOnInit

NgOnit ist ein Lifecycle-Hook, der vom Angular 2-Framework bereitgestellt wird. Ihre Komponente muss implementiert OnInitwerden, um sie verwenden zu können. Dieser Lifecycle-Hook wird aufgerufen, nachdem der Konstruktor aufgerufen und alle Variablen initialisiert wurden. Der Großteil Ihrer Initialisierung sollte hier ablaufen. Sie haben die Gewissheit, dass Angular Ihre Komponente korrekt initialisiert hat, und können mit jeder Logik beginnen, die Sie benötigenOnInit anstatt Dinge zu tun, wenn Ihre Komponente nicht ordnungsgemäß geladen wurde.

Hier ist ein Bild, das die Reihenfolge der Aufrufe beschreibt:

Geben Sie hier die Bildbeschreibung ein

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

TLDR

Wenn Sie das Angular 2-Framework verwenden und mit bestimmten Lebenszyklusereignissen interagieren müssen, verwenden Sie die vom Framework bereitgestellten Methoden, um Probleme zu vermeiden.

Eduardo Dennis
quelle
19

Um dies zu testen, habe ich diesen Code aus dem NativeScript-Tutorial geschrieben :

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;
  }

}

Konsolenausgabe

JS: *** User class constructor property ***  
JS: *** User class constructor constructor ***  
JS: *** Login Component Constructor ***  
JS: *** User class constructor ngOnInit ***  
JS: *** Login Component ngOnInit ***  
abbaf33f
quelle
18

Der Hauptunterschied zwischen Konstruktor und ngOnInitbesteht darin, dass ngOnInites sich um einen Lebenszyklus-Hook handelt, der nach dem Konstruktor ausgeführt wird. Komponenteninterpolierte Vorlagen- und Eingabe-Anfangswerte sind im Konstruktor nicht verfügbar, aber in ngOnInit.

Der praktische Unterschied besteht darin, wie sich dies ngOnInitauf die Struktur des Codes auswirkt. Der meiste Initialisierungscode kann verschoben werden ngOnInit- solange dies keine Rennbedingungen schafft .

Konstruktor-Antimuster

Eine beträchtliche Menge an Initialisierungscode macht es schwierig, die Konstruktormethode zu erweitern, zu lesen und zu testen.

Ein übliches Rezept für Initialisierungslogik aus Klassenkonstruktors trennt , ist es auf ein anderes Verfahren zu bewegen , wie init:

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

  init() {...}
}

ngOnInit kann diesen Zweck in Komponenten und Richtlinien erfüllen:

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

ngOnInit() {
  // rest of initialization code
}

Abhängigkeitsspritze

Die Hauptaufgabe von Klassenkonstruktoren in Angular ist die Abhängigkeitsinjektion. Konstruktoren werden auch für DI-Annotationen in TypeScript verwendet. Fast alle Abhängigkeiten werden der Klasseninstanz als Eigenschaften zugewiesen.

Der durchschnittliche Komponenten- / Direktivenkonstruktor ist bereits groß genug, da er aufgrund von Abhängigkeiten eine mehrzeilige Signatur haben kann. Eine unnötige Intialisierungslogik für den Konstruktorkörper trägt zum Antimuster bei.

Asynchrone Initialisierung

Der Konstruktor für die asynchrone Initialisierung kann häufig als Antimuster betrachtet werden und riecht, da die Klasseninstanziierung vor der asynchronen Routine abgeschlossen wird und dies zu Race-Bedingungen führen kann. Wenn dies nicht der Fall ist ngOnInitund andere Lifecycle-Hooks dafür besser geeignet sind, insbesondere weil sie von der asyncSyntax profitieren können :

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

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

Wenn Race-Bedingungen vorliegen (einschließlich derjenigen, bei denen eine Komponente bei einem Initialisierungsfehler nicht angezeigt werden sollte), sollte die asynchrone Initialisierungsroutine vor der Instanziierung der Komponente stattfinden und in die übergeordnete Komponente, den Router Guard usw. verschoben werden.

Unit Testing

ngOnInitist flexibler als ein Konstruktor und bietet einige Vorteile für Unit-Tests, die in dieser Antwort ausführlich erläutert werden .

Da dies ngOnInitbei der Kompilierung von Komponenten in Komponententests nicht automatisch aufgerufen wird, ngOnInitkönnen aufgerufene Methoden nach der Instanziierung von Komponenten ausspioniert oder verspottet werden.

In Ausnahmefällen ngOnInit kann vollständig gestoppt werden, um die Isolation für andere Komponenteneinheiten (z. B. einige Vorlagenlogik) zu gewährleisten.

Erbe

Untergeordnete Klassen können Konstruktoren nur erweitern, nicht ersetzen.

Da thiskann vorher nicht verwiesen werdensuper() , schränkt dies die Priorität der Initialisierung ein.

In Anbetracht der Tatsache, dass die Angular-Komponente oder -Richtlinie ngOnInitfür die zeitunempfindliche Initialisierungslogik verwendet wird, können untergeordnete Klassen auswählen, ob super.ngOnInit()und wann aufgerufen wird:

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

Dies wäre mit dem Konstruktor allein unmöglich zu implementieren.

Estus Flask
quelle
12

Die obigen Antworten beantworten diesen Aspekt der ursprünglichen Frage nicht wirklich: Was ist ein Lebenszyklus-Hook? Ich habe eine Weile gebraucht, um zu verstehen, was das bedeutet, bis ich es so gesehen habe.

1) Angenommen, Ihre Komponente ist ein Mensch. Menschen haben ein Leben, das viele Lebensphasen umfasst, und dann verfallen wir.

2) Unsere menschliche Komponente könnte das folgende Lebenszyklus-Skript haben: Geboren, Baby, Grundschule, junger Erwachsener, Erwachsener mittleren Alters, älterer Erwachsener, tot, entsorgt.

3) Angenommen, Sie möchten eine Funktion zum Erstellen von Kindern haben. Um zu verhindern, dass dies kompliziert und ziemlich humorvoll wird, möchten Sie, dass Ihre Funktion nur in der Phase des jungen Erwachsenen im Leben der menschlichen Komponente aufgerufen wird. Sie entwickeln also eine Komponente, die nur aktiv ist, wenn sich die übergeordnete Komponente im Stadium für junge Erwachsene befindet. Hooks helfen Ihnen dabei, indem sie diesen Lebensabschnitt signalisieren und Ihre Komponente darauf einwirken lassen.

Lustige Sachen. Wenn Sie Ihrer Fantasie freien Lauf lassen, um so etwas tatsächlich zu codieren, wird es kompliziert und lustig.

Preston
quelle
7

Der Konstruktor ist eine Methode in JavaScript und wird als Merkmal der Klasse in es6 betrachtet. Wenn die Klasse instanziiert wird, wird der Konstruktor sofort ausgeführt, unabhängig davon, ob er im Angular-Framework verwendet wird oder nicht Kontrolle darüber.

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

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

Die "ConstructorTest" -Klasse wird unten instanziiert, ruft also intern den Konstruktor auf (all dies geschieht durch JavaScript (es6) no Angular).

new CONSTRUCTORTEST();

Aus diesem Grund gibt es in Angular.ngOnInit einen ngOnInit- Lifecycle-Hook, wenn Angular die Initialisierung der Komponente abgeschlossen hat.

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

Zuerst instanziieren wir die Klasse wie folgt, die bei sofortigen Läufen der Konstruktormethode passiert.

let instance = new NGONINITTEST();

ngOnInit wird bei Bedarf von Angular wie folgt aufgerufen:

instance.ngOnInit();

Aber Sie fragen sich vielleicht, warum wir den Konstruktor in Angular verwenden?

Die Antwort lautet Abhängigkeitsinjektionen. Wie bereits erwähnt, ruft der Konstruktor die JavaScript-Engine sofort auf, wenn die Klasse instanziiert wird (bevor ngOnInit von Angular aufgerufen wird), sodass Typoskript uns hilft, den Typ der Abhängigkeiten zu ermitteln, die im Konstruktor definiert sind, und schließlich mitteilt Winkel, welche Art von Abhängigkeiten wir in dieser bestimmten Komponente verwenden möchten.

Negin
quelle
7

Zwei Dinge, die hier zu beachten sind:

  1. Der Konstruktor wird immer dann aufgerufen, wenn ein Objekt dieser Klasse erstellt wird.
  2. ngOnInit wird aufgerufen, sobald die Komponente erstellt wurde.

Beide haben unterschiedliche Benutzerfreundlichkeit.

UniCoder
quelle
5

Konstrukteur() ist die Standardmethode im Komponentenlebenszyklus und wird für die Abhängigkeitsinjektion verwendet. Der Konstruktor ist eine Typoskript-Funktion.

ngOnInit () wird nach dem Konstruktor und ngOnInit nach den ersten ngOnChanges aufgerufen.

dh:

Konstruktor () -->ngOnChanges ()--> ngOnInit ()

Wie oben erwähnt, ngOnChanges()wird aufgerufen, wenn sich ein Eingabe- oder Ausgabebindungswert ändert.

Shajin Chandran
quelle
4

Beide Methoden haben unterschiedliche Ziele / Verantwortlichkeiten. Die Aufgabe des Konstruktors (eine sprachunterstützte Funktion) besteht darin, sicherzustellen, dass die Repräsentationsinvariante gültig ist. Andernfalls wird angegeben, um sicherzustellen, dass die Instanz gültig ist, indem den Mitgliedern korrekte Werte zugewiesen werden. Es ist Sache des Entwicklers, zu entscheiden, was "richtig" bedeutet.

Die Aufgabe der onInit () -Methode (die ein Winkelkonzept ist) besteht darin, Methodenaufrufe für ein korrektes Objekt zuzulassen (Repräsentationsinvariante). Jede Methode sollte wiederum sicherstellen, dass die Repräsentationsinvariante gilt, wenn die Methode beendet wird.

Der Konstruktor sollte verwendet werden, um 'korrekte' Objekte zu erstellen. Die onInit-Methode bietet Ihnen die Möglichkeit, Methodenaufrufe an einer genau definierten Instanz aufzurufen.

Bruno Ranschaert
quelle
4

Konstrukteur: Die Konstruktormethode für eine ES6-Klasse (oder in diesem Fall TypeScript) ist ein Feature einer Klasse selbst und kein Angular-Feature. Es liegt außerhalb der Kontrolle von Angular, wenn der Konstruktor aufgerufen wird. Dies bedeutet, dass es kein geeigneter Hook ist, um Sie darüber zu informieren, wenn Angular die Initialisierung der Komponente abgeschlossen hat. Die JavaScript-Engine ruft den Konstruktor auf, nicht Angular direkt. Aus diesem Grund wurde der Lebenszyklus-Hook ngOnInit (und $ onInit in AngularJS) erstellt. Vor diesem Hintergrund gibt es ein geeignetes Szenario für die Verwendung des Konstruktors. In diesem Fall möchten wir die Abhängigkeitsinjektion verwenden - im Wesentlichen zum „Verdrahten“ von Abhängigkeiten in die Komponente.

Da der Konstruktor von der JavaScript-Engine initialisiert wird und TypeScript es uns ermöglicht, Angular mitzuteilen, welche Abhängigkeiten erforderlich sind, um einer bestimmten Eigenschaft zugeordnet zu werden.

ngOnInit dient lediglich dazu, uns zu signalisieren, dass Angular die Initialisierung der Komponente abgeschlossen hat.

Diese Phase umfasst den ersten Durchgang bei der Änderungserkennung für die Eigenschaften, die wir möglicherweise an die Komponente selbst binden, z. B. mithilfe eines @ Input () -Dekorators.

Aus diesem Grund sind die Eigenschaften von @Input () in ngOnInit verfügbar, im Konstruktor jedoch nicht definiert

Vishal Gulati
quelle
2

Der Konstruktor ist der erste, und es kommt manchmal vor, wenn die @ Eingabedaten null sind! Daher verwenden wir den Konstruktor, um Dienste zu deklarieren, und ngOnInit erfolgt danach. Beispiel für einen Kontrahenten:

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

Beispiel für onInit:

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

Ich denke, dass onInit wie InitialComponents () in winForm ist.

user1012506
quelle
1

In den Winkellebenszyklen

1) Winkelinjektor erkennt Konstruktorparameter und instanziiert Klasse.

2) Nächster Winkelanruf-Lebenszyklus

Angular Lifecycle Hooks

ngOnChanges -> Aufruf der Direktivenparameterbindung.

ngOnInit -> Winkel-Rendering starten ...

Rufen Sie eine andere Methode mit dem Zustand des Winkellebenszyklus auf.

Moslemischer Shahsavan
quelle
1

Das constructorwird aufgerufen, wenn Angular die Komponente "instanziiert / konstruiert". Die ngOnInitMethode ist ein Hook, der den Initialisierungsteil des Komponentenlebenszyklus darstellt. Es wird empfohlen, es nur für die Service-Injektion zu verwenden :

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

Selbst wenn es möglich ist, sollten Sie keine "Arbeit" im Inneren erledigen. Wenn Sie eine Aktion starten möchten, die bei der "Initialisierung" der Komponente ausgeführt werden muss, verwenden Sie ngOnInit:

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

Darüber hinaus können Aktionen mit Eingabeeigenschaften , die von einer übergeordneten Komponente stammen, im Konstruktor nicht ausgeführt werden. Sie sollten in ngOnInitMethode oder einem anderen Haken platziert werden. Dies gilt auch für Elemente, die sich auf die Ansicht beziehen (das DOM), z. B. viewchild-Elemente :

@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
quelle
0

constructor() wird verwendet, um die Abhängigkeitsinjektion durchzuführen.

ngOnInit(), ngOnChanges()Und ngOnDestroy()usw. sind Lifecycle - Methoden. ngOnChanges()wird als erster aufgerufen, bevor sich ngOnInit()der Wert einer gebundenen Eigenschaft ändert, wird er NICHT aufgerufen, wenn keine Änderung vorliegt. ngOnDestroy()wird aufgerufen, wenn die Komponente entfernt wird. Um es zu verwenden, OnDestroymuss es implementvon der Klasse bearbeitet werden.

Xameeramir
quelle
1
stimme zu, das ist kurz und klar. Beispielsweise dient constructor () zum Hinzufügen von Serviceobjekten, ngOnInit () zum Bearbeiten von Komponenten mit den erforderlichen Servicefunktionsaufrufen.
Steve
0

Ich fand die Antwort und versuchte sie ins Englische zu übersetzen: Diese Frage stellte sich auch in technischen Interviews noch. Tatsächlich gibt es eine große Ähnlichkeit zwischen den beiden, aber es gibt auch einige Unterschiede.

  • Der Konstruktor ist Teil von ECMAScript. Andererseits ist ngOnInit () ein Winkelbegriff.

  • Wir können die Konstruktoren in allen Klassen aufrufen, auch wenn wir Angular nicht verwenden

  • Lebenszyklus: Der Konstruktor wird vor ngOnInt () aufgerufen.

  • Im Konstruktor können wir keine HTML-Elemente aufrufen. In ngOnInit () können wir dies jedoch.

  • Im Allgemeinen Aufrufe von Diensten in ngOnInit () und nicht im Konstruktor

    Quelle: http://www.angular-tuto.com/Angular/Component#Diff

doudou
quelle
0

Konstrukteur

Die Konstruktorfunktion wird mit jeder Klasse geliefert. Konstruktoren sind nicht spezifisch für Angular, sondern Konzepte, die aus objektorientierten Entwürfen abgeleitet wurden. Der Konstruktor erstellt eine Instanz der Komponentenklasse.

OnInit

Die ngOnInitFunktion ist eine der Lebenszyklusmethoden einer Angular-Komponente. Mit Lebenszyklusmethoden (oder Hooks) in Angular-Komponenten können Sie einen Code in verschiedenen Phasen der Lebensdauer einer Komponente ausführen. Im Gegensatz zur Konstruktormethode ngOnInitstammt die Methode von einer Angular-Schnittstelle ( OnInit), die die Komponente implementieren muss, um diese Methode verwenden zu können. Die ngOnInitMethode wird kurz nach dem Erstellen der Komponente aufgerufen.

DeC
quelle
0

Der Konstruktor wird ausgeführt, wenn die Klasse instanziiert wird. Es hat nichts mit dem Winkel zu tun. Es ist die Funktion von Javascript und Angular hat keine Kontrolle darüber

Das ngOnInit ist Angular-spezifisch und wird aufgerufen, wenn das Angular die Komponente mit all ihren Eingabeeigenschaften initialisiert hat

Die @ Input-Eigenschaften sind unter dem ngOnInit-Lifecycle-Hook verfügbar. Auf diese Weise können Sie einige Initialisierungsaufgaben erledigen, z. B. Daten vom Back-End-Server usw. in der Ansicht anzeigen

@ Input-Eigenschaften werden im Konstruktor als undefiniert angezeigt

dasunse
quelle
-1

Der Konstruktor ist eine Funktion, die ausgeführt wird, wenn eine Komponente (oder eine andere Klasse) erstellt wird.

ngOnInit ist eine Funktion, die zu einer Gruppen-Lebenszyklus-Methodengruppe gehört und in einem anderen Moment unserer Komponente ausgeführt wird (daher Name Life-Cycle). Hier ist eine Liste von allen:

Geben Sie hier die Bildbeschreibung ein Der Konstruktor wird vor jeder Lebenszyklusfunktion ausgeführt.

Przemek Struciński
quelle