Question Différence entre constructeur et ngOnInit


Angular fournit un crochet de cycle de vie ngOnInit par défaut.

Pourquoi devrais-je ngOnInit être utilisé, si nous avons déjà un constructor?


553
2018-03-03 05:14


origine


Réponses:


le Constructor est une méthode par défaut de la classe qui est exécutée lorsque la classe est instanciée et garantit l'initialisation correcte des champs de la classe et de ses sous-classes. Angulaire ou mieux Dépendance Injector (DI) analyse les paramètres du constructeur et quand il crée une nouvelle instance en appelant new MyClass() il essaie de trouver des fournisseurs qui correspondent aux types de paramètres du constructeur, les résout et les transmet au constructeur comme

new MyClass(someArg);

ngOnInit est un hook de cycle de vie appelé par Angular2 pour indiquer que Angular est fait en créant le composant.

Nous devons importer OnInit afin d'utiliser comme ça (en train de mettre en œuvre OnInit n'est pas obligatoire mais considéré comme une bonne pratique):

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

puis d'utiliser la méthode de OnInit nous devons mettre en œuvre dans la classe comme ça.

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

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

Implémentez cette interface pour exécuter une logique d'initialisation personnalisée après l'initialisation des propriétés liées aux données de votre directive.   ngOnInit est appelé juste après que les propriétés liées aux données de la directive ont été vérifiées pour la première fois,   et avant que l'un de ses enfants ait été vérifié.   Il est invoqué une seule fois lorsque la directive est instanciée.

La plupart du temps nous utilisons ngOnInit pour toute l'initialisation / déclaration et éviter les choses à travailler dans le constructeur. Le constructeur ne devrait être utilisé que pour initialiser les membres de la classe mais ne devrait pas faire de "travail" réel.

Donc, vous devriez utiliser constructor() pour configurer Dependency Injection et pas grand-chose d'autre. ngOnInit () est le meilleur endroit pour "démarrer" - c'est où / quand les liaisons des composants sont résolues.

Pour plus d'informations, référez-vous ici:


625
2018-03-03 05:20



Je pense que le meilleur exemple serait l'utilisation des services. Disons que je veux récupérer des données de mon serveur quand mon composant est 'Activé'. Disons que je veux aussi faire des choses supplémentaires aux données après l'avoir reçu du serveur, peut-être que j'obtiens une erreur et que je veux l'enregistrer différemment.

C'est vraiment facile avec ngOnInit sur un constructeur, cela limite aussi le nombre de couches de callback que j'ai besoin d'ajouter à mon application.

Par exemple:

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


}

Avec mon constructeur, je pourrais simplement appeler mon _userService et remplir ma user_list, mais peut-être que je veux faire des choses supplémentaires avec. Comme si tout était upper_case, je ne suis pas tout à fait sûr de la façon dont mes données arrivent.

Donc, il est beaucoup plus facile d'utiliser ngOnInit.

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


}

Cela rend la chose beaucoup plus facile à voir, et donc j'appelle simplement ma fonction dans mon composant quand j'initialise au lieu d'avoir à chercher ailleurs. Vraiment, c'est juste un autre outil que vous pouvez utiliser pour le rendre plus facile à lire et à utiliser dans le futur. Aussi, je trouve que c'est vraiment une mauvaise pratique de mettre des appels de fonction dans un constructeur!


69
2018-03-03 05:30



L'article La différence essentielle entre Constructor et ngOnInit en Angularexplore la différence à partir de perspectives multiples. Cette réponse fournit l'explication de différence la plus importante liée au processus d'initialisation de composant qui montre également l'utilisation différente.

Le processus de bootstrap angulaire consiste en deux étapes principales:

  • construction de l'arbre des composants
  • exécution de la détection de changement

Le constructeur du composant est appelé quand Angular construit l'arbre des composants. Tous les hooks de cycle de vie sont appelés dans le cadre de la détection de changement en cours.

Lorsque Angular construit l'arbre des composants, l'injecteur du module racine est déjà configuré pour injecter des dépendances globales. De plus, lorsque Angular instancie une classe de composant enfant, l'injecteur du composant parent est déjà configuré pour injecter des fournisseurs définis sur le composant parent, y compris le composant parent lui-même. Les constructeurs de composants sont la seule méthode appelée dans le contexte de l'injecteur, donc si vous avez besoin d'une dépendance, c'est le seul endroit pour obtenir ces dépendances.

Quand Angular commence la détection des changements, l'arbre des composants est construit et les constructeurs de tous les composants de l'arbre ont été appelés. Les nœuds de template de chaque composant sont également ajoutés au DOM. le @Input Le mécanisme de communication est traité lors de la détection des modifications. Vous ne pouvez donc pas vous attendre à ce que les propriétés soient disponibles dans le constructeur. Il sera disponible après ngOnInit.

Voyons un exemple rapide. Supposons que vous avez le modèle suivant:

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

Angular démarre donc l'amorçage de l'application. Comme je l'ai dit, il crée d'abord des classes pour chaque composant. Donc ça appelle MyAppComponent constructeur. Il crée également un noeud DOM qui est l'élément hôte du my-app composant. Ensuite, il procède à la création d'un élément hôte pour le child-comp et appeler ChildComponent constructeur. A ce stade, il n'est pas vraiment concerné par i liaison d'entrée et tous les hooks de cycle de vie. Ainsi, lorsque ce processus est terminé, Angular se retrouve avec l'arborescence de vues de composants suivante:

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

Seulement alors exécute la détection de changement et met à jour les liaisons pour le my-app et appels ngOnInit sur la classe MyAppComponent. Ensuite, il procède à la mise à jour des liaisons pour le child-comp et appels ngOnInit sur la classe ChildComponent.

Vous pouvez faire votre logique d'initialisation dans le constructeur ou ngOnInit en fonction de ce dont vous avez besoin disponible. Par exemple l'article Voici comment obtenir ViewContainerRef avant d'évaluer la requête @ViewChild montre quel type de logique d'initialisation peut être requis pour être exécuté dans le constructeur.

Voici quelques articles qui vous aideront à mieux comprendre le sujet:


60
2017-08-01 06:13



Le premier (constructeur) est lié à l'instanciation de classe et n'a rien à voir avec Angular2. Je veux dire qu'un constructeur peut être utilisé sur n'importe quelle classe. Vous pouvez y mettre un peu de traitement d'initialisation pour l'instance nouvellement créée.

Le second correspond à un hook de cycle de vie des composants Angular2:

Cité sur le site officiel d'Angular:

  • ngOnChanges est appelée quand une valeur de liaison d'entrée ou de sortie change
  • ngOnInit est appelé après le premier ngOnChanges

Donc, vous devriez utiliser ngOnInit si le traitement d'initialisation repose sur des liaisons du composant (par exemple, les paramètres de composant définis avec @Input), sinon le constructeur serait suffisant ...


41
2018-03-03 06:36



D'ACCORD, tout d'abord ngOnInit fait partie de Cycle de vie angulaire, tandis que constructor fait partie de ES6 Classe JavaScript, donc la différence majeure commence ici! ...

Regardez le tableau ci-dessous que j'ai créé qui montre le cycle de vie de Angular.

ngOnInit vs constructor

En Angular2 + nous utilisons constructor faire la DI(Dependency Injection) pour nous, alors que dans Angular 1 cela se passait en appelant la méthode String et en vérifiant quelle dépendance était injectée.

Comme vous le voyez dans le diagramme ci-dessus, ngOnInit se passe après que le constructeur est prêt et ngOnChnages et se faire virer après que le composant est prêt pour nous. Toute initialisation peut arriver à ce stade, un simple échantillon injecte un service et l'initialise sur init.

OK, je partage également un exemple de code pour vous de voir, voir comment nous utilisons ngOnInit et constructor dans le code ci-dessous:

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

37
2018-06-05 10:04



Réponse courte et simple serait,

Constructor : constructor est un default method courses (par deafult) lorsque le composant est en cours de construction. Lorsque vous créez an instance d'une classe cette fois aussi constructor(default method) serait appelé. Donc, en d'autres termes, lorsque le composant est en cours constructed or/and an instance is created constructor(default method) est appelé et le code pertinent écrit à l'intérieur est appelé. Fondamentalement et généralement dans Angular2 il injectait des choses comme services lorsque le composant est en cours de construction pour une utilisation ultérieure.

OnInit: ngOnInit est le crochet de cycle de vie du composant qui fonctionne d'abord après constructor(default method) lorsque le composant est en cours d'initialisation.

Ainsi, votre constructeur sera appelé en premier et Oninit sera appelé plus tard après la méthode constructeur.

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

Ressources: LifeCycle crochet

Vous pouvez vérifier ceci petite démo ce qui montre la mise en œuvre des deux choses.


24
2018-03-03 05:20



Pour tester cela, j'ai écrit ce code, en empruntant à la Didacticiel 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;
  }

}

Sortie de la console

JS: *** User class constructor property ***  
JS: *** User class constructor constructor ***  
JS: *** Login Component Constructor ***  
JS: *** User class constructor ngOnInit ***  
JS: *** Login Component ngOnInit ***  

15
2018-05-24 14:58



Les réponses ci-dessus ne répondent pas vraiment à cet aspect de la question initiale: Qu'est-ce qu'un hook de cycle de vie? Il m'a fallu du temps pour comprendre ce que cela signifiait jusqu'à ce que j'y pense de cette façon.

1) Dites que votre composant est un humain. Les humains ont des vies qui incluent de nombreuses étapes de la vie, et puis nous expirons.

2) Notre composante humaine pourrait avoir le script de cycle de vie suivant: Naissance, Bébé, École primaire, Jeune adulte, Adulte d'âge moyen, Adulte aîné, Mort, Disposition de.

3) Dites que vous voulez avoir une fonction pour créer des enfants. Pour éviter que cela ne devienne compliqué, et plutôt humoristique, vous voulez que votre fonction ne soit appelée que pendant la phase Jeune adulte de la vie de l'être humain. Vous développez donc un composant qui n'est actif que lorsque le composant parent est au stade Jeune adulte. Les crochets vous aident à faire cela en signalant cette étape de la vie et en laissant votre composante agir dessus.

Truc amusant. Si vous laissez votre imagination aller coder quelque chose comme ça, ça devient compliqué et drôle.


11
2017-12-09 19:52



Comme beaucoup d'autres langages, vous pouvez initialiser des variables au niveau de la classe, au constructeur ou à une méthode. C'est au développeur de décider ce qui est le mieux dans son cas particulier. Mais ci-dessous sont une liste de meilleures pratiques quand il s'agit de décider.

 Variables de niveau classe

Habituellement, vous déclarerez ici toutes vos variables qui seront utilisées dans le reste de votre composant. Vous pouvez les initialiser si la valeur ne dépend de rien d'autre, ou utiliser le mot-clé const pour créer des constantes si elles ne changent pas.

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

Constructeur

Normalement, il est préférable de ne rien faire dans le constructeur et de l'utiliser uniquement pour les classes qui seront injectées. La plupart du temps, votre constructeur devrait ressembler à ceci:

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

cela créera automatiquement les variables de niveau de classe, de sorte que vous aurez accès à customService.myMethod() sans avoir à le faire manuellement.

NgOnInit

NgOnit est un hook de cycle de vie fourni par le framework Angular 2. Votre composant doit mettre en œuvre OnInit afin de l'utiliser. Ce hook de cycle de vie est appelé après l'appel du constructeur et toutes les variables sont initialisées. La majeure partie de votre initialisation devrait aller ici. Vous aurez la certitude qu'Angular a correctement initialisé votre composant et vous pouvez commencer à faire toute la logique dont vous avez besoin OnInit par rapport à faire des choses lorsque votre composant n'a pas fini de se charger correctement.

Voici une image détaillant l'ordre de ce qu'on appelle:

enter image description here

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

TLDR

Si vous utilisez Angular 2 Framework et devez interagir avec certains événements de cycle de vie, utilisez les méthodes fournies par le framework pour éviter les problèmes.


11
2018-03-06 21:59



Je vais juste ajouter une chose importante qui a été omise dans les explications ci-dessus et explique quand vous DOIT utilisation ngOnInit.

Si vous effectuez une manipulation du DOM du composant via, par exemple, VoirEnfants, ContentChildren ou ElementRef, vos éléments natifs ne seront pas disponibles pendant la phase du constructeur.

Cependant, depuis ngOnInit se produit une fois que le composant a été créé et les contrôles (ngOnChanges) ont été appelés, vous pouvez accéder au DOM à ce stade.

export class App implements OnInit {
  @ViewChild('myTemplate') myTemplate: TemplateRef<any>;

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

  ngOnInit() {
     // this.elementRef.nativeElement can be used from here on
     // this.myTemplate can be used from here on
  }
}

11
2018-01-29 11:16



La principale différence entre le constructeur et ngOnInit est-ce ngOnInit est crochet de cycle de vie et court après constructeur. Le modèle interpolé de composant et les valeurs initiales d'entrée ne sont pas disponibles dans le constructeur, mais elles sont disponibles dans ngOnInit.

La différence pratique est comment ngOnInit affecte la façon dont le code est structuré. La plupart des codes d'initialisation peuvent être déplacés vers ngOnInit - tant que cela ne crée pas de conditions de course.

Constructeur antipattern

Une quantité importante de code d'initialisation rend la méthode du constructeur difficile à étendre, à lire et à tester.

Une recette habituelle pour séparer la logique d'initialisation du constructeur de classe est de le déplacer vers une autre méthode comme init:

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

  init() {...}
}

ngOnInitpeut servir à cette fin dans les composants et les directives:

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

ngOnInit() {
  // rest of initialization code
}

Injection de dépendance

Le rôle principal des constructeurs de classe dans Angular est l'injection de dépendance. Les constructeurs sont également utilisés pour l'annotation DI dans TypeScript. Presque toutes les dépendances sont affectées en tant que propriétés à l'instance de classe.

Le constructeur moyen de composant / directive est déjà assez grand parce qu'il peut avoir une signature multiligne en raison des dépendances, en mettant une logique d'initialisation inutile au corps du constructeur contribue à l'antipattern.

Initialisation asynchrone

Le constructeur d'initialisation asynchrone peut souvent être considéré comme antipattern et avoir une odeur parce que l'instanciation de classe se termine avant la routine asynchrone, et cela peut créer des conditions de concurrence. Si ce n'est pas le cas, ngOnInit et d'autres hameçons de cycle de vie sont de meilleurs endroits pour cela, en particulier parce qu'ils peuvent bénéficier de async syntaxe:

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

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

S'il existe des conditions de concurrence (y compris celle qu'un composant ne doit pas apparaître sur l'erreur d'initialisation), la routine d'initialisation asynchrone doit avoir lieu avant l'instanciation du composant et être déplacée vers le composant parent, la protection du routeur, etc.

Tests unitaires

ngOnInit est plus flexible qu'un constructeur et offre des avantages pour les tests unitaires qui sont expliqués en détail dans cette réponse.

Étant donné que ngOnInit n'est pas appelé automatiquement lors de la compilation de composants dans les tests unitaires, les méthodes appelées ngOnInit peut être espionné ou mocké après l'instanciation du composant.

Dans des cas exceptionnels ngOnInit peut être entièrement stubbed pour fournir l'isolation pour d'autres unités de composant (par exemple, une certaine logique de modèle).

Héritage

Les classes enfant peuvent seulement augmenter les constructeurs, pas les remplacer.

Depuis this ne peut pas être référé avant super(), cela met des restrictions sur la priorité d'initialisation.

Considérant que le composant angulaire ou la directive utilise ngOnInit pour une logique d'initialisation insensible au temps, les classes enfants peuvent choisir si super.ngOnInit() est appelé et quand:

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

Cela serait impossible à implémenter avec le constructeur seul.


10
2018-02-09 12:35