Yapıcı ve ngOnInit arasındaki fark


Yanıtlar:


1109

ConstructorSınıf örneği ve sınıfının ve alt sınıflarının alanların doğru başlatmayı sağlar edildiğinde yürütülür sınıfının varsayılan bir yöntemdir. Açısal veya daha iyi Bağımlılık Enjektörü (DI), yapıcı parametrelerini analiz eder ve yeni bir örnek oluşturduğunda new MyClass(), yapıcı parametre türleriyle eşleşen sağlayıcıları bulmaya çalışır, bunları çözer ve bunları yapıcıya aktarır.

new MyClass(someArg);

ngOnInit Angular'ın bileşeni oluşturduğunu göstermek için Angular tarafından çağrılan bir yaşam döngüsü kancasıdır.

Kullanmak için OnInitböyle ithal etmeliyiz (aslında uygulama OnInitzorunlu değildir, ancak iyi uygulama olarak kabul edilir):

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

o zaman bizi yöntem yapmak OnInitiçin sınıfı şu şekilde uygulamalıyız:

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

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

Direktifinizin veriye bağlı özellikleri başlatıldıktan sonra özel başlatma mantığını yürütmek için bu arabirimi uygulayın. ngOnInit, direktifin veriye bağlı özellikleri ilk kez kontrol edildikten hemen sonra ve çocuklarından herhangi biri kontrol edilmeden hemen önce çağrılır. Direktif somutlaştırıldığında yalnızca bir kez çağrılır.

Çoğunlukla ngOnInittüm başlatma / bildirim için kullanırız ve yapıcıda çalışmaktan kaçınırız. Yapıcı yalnızca sınıf üyelerini başlatmak için kullanılmalı, ancak gerçek "iş" yapmamalıdır.

Bu yüzden constructor()Bağımlılık Enjeksiyonunu ayarlamak için kullanmalısınız ve çok fazla değil. ngOnInit (), "başlamak" için daha iyi bir yerdir - bileşenlerin bağlarının çözüldüğü yer / zaman.

Daha fazla bilgi için buraya bakın:


62
Tam olarak, sınıf temelli dillerin çoğu (özellikle TS), son alanlar gibi (TS'in sahip olup olmadığını bilmiyorum) ve benzerleri gibi oldukça zor sorunların ortaya çıkabileceği diğer sınıfları genişleten sınıfların uygun başlatma sırasını sağlamak için yapılandırıcılara sahiptir. Yapılandırıcılar Angular2 ile ilişkili değildir, bir TypeScript özelliğidir. Yaşam döngüsü kancaları, bazı başlatmalar yapıldıktan sonra veya bileşenin belirli durumlar üzerinde hareket etmesine izin vermek ve ona uygun zamanlarda bazı görevleri yapma şansı vermek için bir olay gerçekleştiğinde Angular tarafından çağrılır.
Günter Zöchbauer

12
Angular.io/docs/ts/latest/guide/server-communication.html dosyasında da bunu açıklayan bir blok alıntı vardır : "Bileşenler, kurucuları basit olduğunda ve tüm gerçek işlerde (özellikle uzak sunucu) ayrı bir yöntemle işlenir. " - Bu durumda bu yöntem ngOnInit ()
yoonjesung

3
, Angular2 tarafından bileşenin oluşturulduğunu belirten bir yaşam döngüsü kancasıdır. - tam olarak bu değil. bağları başlattığını gösterir. Bileşen daha önce oluşturuldu. Cevabımı
Max Koretskyi

22
Tüm "en iyi uygulamalarda" olduğu gibi, yapıcıda neden "iş" yapmamanız gerektiğini açıklamanın iyi bir fikir olacağını düşünüyorum . Açısal ekip liderinin bu makalesi yoğundur, ancak yardımcı olabilir: misko.hevery.com/code-reviewers-guide/… OnInit'i uygulamak için gerekli eklentilere daha az önem verilmelidir (bu bulmak kolaydır) ve daha fazlası veri bağlayıcıların kurucuda bulunmaması kritik gerçeği.
Reikim

2
Sıkı mod tsconfig.jsondosya gibi doğruysa "strict": true, sınıf üyelerini gibi constructordeğil, içinde başlatmanız gerekir . ngOnitFormGroup
Rohit Sharma

171

Oluşturucu ve ngOnInit arasındaki Açısal fark, makalede , farklı açılardan farkı inceliyor. Bu cevap, kullanımdaki farklılığı gösteren bileşen başlatma işlemiyle ilgili en önemli fark açıklamasını sağlar.

Açısal önyükleme işlemi iki ana aşamadan oluşur:

  • bileşenleri ağaç oluşturma
  • çalışan değişiklik tespiti

Açısal bileşen ağacını oluşturduğunda bileşenin yapıcısı çağrılır. Tüm yaşam döngüsü kancaları, çalışma değişikliği algılamanın bir parçası olarak adlandırılır.

Açısal yapı bileşenleri ağacında kök modül enjektörü zaten yapılandırılmıştır, böylece herhangi bir genel bağımlılığı enjekte edebilirsiniz. Ayrıca, Angular bir alt bileşen sınıfını başlattığında, ana bileşenin enjektörü de önceden ayarlanmıştır, böylece üst bileşenin kendisi de dahil olmak üzere üst bileşen üzerinde tanımlanan sağlayıcıları enjekte edebilirsiniz. Bileşen yapıcılar, enjektör bağlamında çağrılan tek yöntemdir, bu nedenle herhangi bir bağımlılığa ihtiyacınız varsa, bu bağımlılıkları almak için tek yer budur.

Açısal değişiklik algılaması başladığında, bileşenler ağacı oluşturulur ve ağaçtaki tüm bileşenler için yapıcılar çağrılır. Ayrıca her bileşenin şablon düğümleri DOM'a eklenir. @InputEğer yapıcı mevcut özelliklere sahip bekleyemezsiniz böylece iletişim mekanizması değişimi algılama sırasında işlenir. Daha sonra sunulacak ngOnInit.

Hızlı bir örnek görelim. Aşağıdaki şablona sahip olduğunuzu varsayalım:

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

Böylece Açısal uygulamayı başlatmaya başlar. Dediğim gibi her bileşen için sınıflar oluşturur. Yani MyAppComponentyapıcı diyor . Ayrıca, my-appbileşenin ana öğesi olan bir DOM düğümü oluşturur . Ardından child-compve çağıran ChildComponentkurucu için bir ana bilgisayar öğesi oluşturmaya devam eder . Bu aşamada, igiriş bağlaması ve herhangi bir yaşam döngüsü kancası ile gerçekten ilgili değildir . Bu işlem bittiğinde Angular, aşağıdaki bileşen görünümleri ağacıyla sonuçlanır:

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

Ancak bundan sonra MyAppComponent sınıfındaki değişiklikler my-appve arama bağlamaları ve çağrıları günceller ngOnInit. Daha sonra ChildComponent sınıfının child-compve çağrılarının bağlantılarını güncellemeye devam eder ngOnInit.

Başlatma mantığınızı yapıcıda veya ngOnInitneye ihtiyacınız olduğuna bağlı olarak yapabilirsiniz. Örneğin @ViewChild sorgusu değerlendirilmeden önce ViewContainerRef'in nasıl alınacağı makalesi , yapıcıda gerçekleştirilmesi gereken başlatma türünün ne tür olduğunu gösterir.

Konuyu daha iyi anlamanıza yardımcı olacak bazı makaleler şunlardır:


33
kabul edilen cevap bu olmalıdır. aslında mantraları tekrarlamak ve söylemek yerine NEDEN'i açıklar the constructor should only be used to inject dependencies.
Stavm

1
@ yannick1976, teşekkürler! Referans verilen makalelere göz atın
Max Koretskyi

@flobacca, lütfen soruyu yeniden ifade edebilir misiniz, ne istediğini anlamak zor
Max Koretskyi

Yanılıyorsam lütfen beni düzeltin. Bileşen ağacının ilk önce kurulduğunu ve daha sonra algılama işlemini değiştirdiğini anladım. Önce AppComponent kurucusunun çağrıldığını (çözümlenmiş bağımlılıklarla birlikte), sonra ChildComponent kurucusunu çağırır (bağımlılıklarla birlikte), sonra AppComponent için Girdi bağlamaları ve sonra OnInit çağrılır. Ama benim endişem, her iki bileşene de yaşam döngüsü kancaları eklersem, akış AppComponentConstructor - -> AppComponentOnInit - → ChildComponentConstructor - → ChildComponentOnInit AppComponentOnInit neden ChildComponentConstructor
user2485435 10:19

1
@MaxKoretskyiakaWizard haklıydın. Uygulama kurulumumda bazı hatalar yaptım. sizin tanımladığınız şekilde çalışıyor. angular-c7zjsx.stackblitz.io
user2485435

94

Bence en iyi örnek hizmetleri kullanmak olacaktır. Bileşenim 'Etkinleştirildiğinde' sunucumdan veri almak istediğimi varsayalım. Diyelim ki sunucudan aldıktan sonra verilere bazı ek şeyler yapmak istiyorum, belki bir hata alıyorum ve farklı şekilde oturum açmak istiyorum.

Bir kurucu üzerinden ngOnInit ile gerçekten kolaydır, ayrıca uygulamama kaç tane geri arama katmanı eklemem gerektiğini de sınırlar.

Örneğin:

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


}

benim kurucu ile _userService telefonumu arayabilir ve kullanıcı listemi doldurabilirdim, ama belki onunla ekstra şeyler yapmak istiyorum. Her şeyin upper_case olduğundan emin olun, verilerimin nasıl geldiğinden tam olarak emin değilim.

Bu nedenle ngOnInit kullanımını kolaylaştırır.

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


}

Görmek çok daha kolay ve bu yüzden başlattığımda başka bir yerde kazmak yerine işlevimi bileşenim içinde çağırıyorum. Gerçekten de, gelecekte okumayı ve kullanmayı kolaylaştırmak için kullanabileceğiniz başka bir araç. Ayrıca bir yapıcı içinde işlev çağrıları koymak gerçekten kötü bir uygulama bulmak!


Kullanıcı_listesini Gözlemlenebilir olarak ayarladıysanız örneğiniz basitleştirilebilir. Angular2'de asenkron boru vardır, bu yüzden orada herhangi bir sorun olmaz.
DarkNeuron

@Morgan, sadece burada küçük bir şey öğrenmem için, neden önce bir işlev oluşturup getUsersonu içine yerleştiriyorsunuz ngOnInit? Sadece ngOnInit'e yazmak daha az kod değil mi? Ben jsut insanların neden bu şekilde yaptığını merak ediyorum? İsterseniz kodu tekrar kullanabilmeniz için mi? Teşekkürler.
Alfa Bravo

31
Aşağıdaki cevapta görüldüğü gibi, yapıcıdaysa bu bir fark yaratmaz. Bu amaca gerçek bir cevap değil.
Jimmy Kane

8
Bunun soruyu nasıl cevapladığını anlamıyorum. Kodu neden giremediniz constructor?
CodyBugstein

1
@Morgan neden yapamıyorsunconstructor(private _userService: UserService){ this.getUsers(); };
Ashley

82

Tamam, her şeyden önce ngOnInitbir parçasıdır Açısal yaşam döngüsü sırasında, constructorbir parçasıdır ES6 önemli fark burada başlar, böylece JavaScript sınıfının! ...

Açısalın yaşam döngüsünü gösteren oluşturduğum aşağıdaki tabloya bakın.

ngOnInit ve kurucu

Angular2 + 'da bizim constructoriçin yapıyoruz, DI(Dependency Injection)Angular 1'de ise String yöntemini çağırmak ve hangi bağımlılığın enjekte edildiğini kontrol etmek yoluyla gerçekleşiyordu.

Yukarıdaki şemada gördüğünüz gibi ngOnInit, kurucu hazır ngOnChnagesolduktan ve bileşen bizim için hazır olduktan sonra işten çıkarıldıktan sonra oluyor. Tüm başlatma bu aşamada gerçekleşebilir, basit bir örnek bir hizmeti enjekte eder ve init üzerinde başlatır.

Tamam, ben de bakmak için nasıl bir örnek kodu paylaşmak, nasıl ngOnInitve constructoraşağıdaki kodda nasıl bakın:

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

1
Teşekkürler. bu en iyi cevap olmalı.
Don Dilanga

58

Birincisi (kurucu) sınıf örneklemesi ile ilgilidir ve Angular2 ile ilgisi yoktur. Yani bir kurucu her sınıfta kullanılabilir. Yeni oluşturulan örnek için bazı başlatma işlemleri koyabilirsiniz.

İkincisi, Angular2 bileşenlerinin yaşam döngüsü kancasına karşılık gelir:

Resmi açısal web sitesinden alıntı:

  • ngOnChanges girdi veya çıktı bağlama değeri değiştiğinde çağrılır
  • ngOnInit ilkinden sonra çağırılır ngOnChanges

Bu nedenle ngOnInit, başlatma işlemi bileşenin bağlarına dayanıyorsa kullanmalısınız (örneğin @Input, ile tanımlanan bileşen parametreleri ), aksi takdirde yapıcı yeterli olacaktır ...


49

Sadece yukarıdaki açıklamalarda atlanır ve ne zaman açıklanır edildi önemli bir şeyi katacak GEREKİR kullanın ngOnInit.

Bileşenin DOM'sinde örneğin ViewChildren , ContentChildren veya ElementRef aracılığıyla herhangi bir değişiklik yapıyorsanız , yerel öğeleriniz yapıcı aşamasında kullanılamaz.

Ancak, ngOnInitbileşen oluşturulduktan ve checks ( ngOnChanges) çağrıldıktan sonra bu noktada DOM'a erişebilirsiniz.

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

3
Hayır! İçin @ViewChildrenözellikle, kullanmak gerekir ngAfterViewInityöntemi. Buraya bakın: stackoverflow.com/questions/46314734/…
AsGoodAsIt

1
Teşekkürler, @AsGoodAsItBu işaret ettiğiniz için alır. Şimdi cevabı geliştirdim
Miroslav Jonas

38

Kısa ve basit bir cevap olurdu,

Constructor: constructorA, default method(çalışır deafult göre bileşen inşa edilirken). Bir an instancesınıf oluşturduğunuzda o zaman da constructor(default method)denir. Başka bir deyişle, bileşen constructed or/and an instance is created constructor(default method)çağrıldığında ve içine yazılan ilgili kod çağrıldığında. Temel olarak ve genellikle içinde , daha fazla kullanım için bileşen inşa edildiğinde olduğu Angular2gibi şeyler enjekte etmek servicesiçin kullanılır.

OnInit: ngOnInit, bileşen constructor(default method)başlatıldıktan sonra ilk olarak çalışan bileşenin yaşam döngüsü kancasıdır .

Böylece, yapıcı ilk önce çağrılır ve Oninit daha sonra yapıcı yönteminden sonra çağrılır.

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

Kaynaklar: LifeCycle hook

Her iki şeyin de uygulanmasını gösteren bu küçük demosu kontrol edebilirsiniz .


5
"Yapıcı bileşen başlatıldığında çalışan veya çağrılan bir şeydir" diye düşünüyorum. yanıltıcıdır. Yapıcı, bileşenin değil, sınıfın bir özelliğidir. Sınıf örneğinin ancak yapıcı çağrıldıktan sonra bir bileşen haline geldiğini ve Angular'ın başlatılmasını yaptığını söyleyebilirim.
Günter Zöchbauer

Evet, şimdi kontrol edebileceğiniz ifadeyi değiştirdi.
micronyks

1
Hmm, IMHO hala aynı "yapıcı (varsayılan yöntem) bileşen oluşturulduğunda çalışan veya çağrılan bir şeydir.". Yalnızca bir bileşen oluşturulduğunda değil, aynı zamanda hizmetler için veya benzeri bir kod new MyClass()yürütüldüğünde çağrılır . Sanırım yapıcıların bileşenler, sınıflar ve bu sınıfların örneklerini başlatma ile ilgili olduğunu söylemek yanıltıcıdır. Bir bileşen böyle bir sınıf olur. Aksi takdirde iyi bir cevap olduğunu düşünüyorum.
Günter Zöchbauer

2
Evet kesinlikle. Bir sınıf nesnesi oluşturduğunuzda o zamanın constructorda çağrıldığını belirtmeyi unutmamalıyız. Ancak bu cevap açısal2 bağlamında yazılmıştır. En iyi cevabı bilmek için OOP'ların temellerini bilmelisiniz. Yine de cevabı güncelleyeceğim.
micronyks

@ GünterZöchbauer, bileşenin değil, sınıfın bir özelliği olan doğru bir iddia olduğunu düşünmüyorum . Programlama dili açısından evet, bu doğrudur. Ancak, herhangi bir yaşam döngüsü kancası olmadan bileşenlerle başarılı bir şekilde çalışabilirim. Ancak DI'ye ihtiyacım olursa yapıcı olmadan bir bileşenle çalışamam çünkü enjekte edilebilir tek yer bu. Cevabımı
Max Koretskyi

20

Diğer birçok dil gibi, değişkenleri sınıf düzeyinde, yapıcıda veya bir yöntemde başlatabilirsiniz. Özel durumlarında neyin en iyi olduğuna karar vermek geliştiriciye bağlıdır. Ancak, aşağıda söz konusu olduğunda en iyi uygulamaların bir listesi verilmiştir.

Sınıf seviyesi değişkenleri

Genellikle, diğer bileşenlerinizde kullanılacak tüm değişkenlerinizi burada bildirirsiniz. Değer başka bir şeye bağlı değilse bunları başlatabilir veya değişmezlerse sabitler oluşturmak için const anahtar sözcüğünü kullanabilirsiniz.

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

inşaatçı

Normalde yapıcıda hiçbir şey yapmamak ve sadece enjekte edilecek sınıflar için kullanmak en iyi uygulamadır. Çoğu zaman kurucunuz şöyle görünmelidir:

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

bu otomatik olarak sınıf seviyesi değişkenlerini oluşturur, böylece customService.myMethod()manuel olarak yapmak zorunda kalmadan erişebilirsiniz .

NgOnInit

NgOnit, Açısal 2 çerçevesi tarafından sağlanan bir yaşam döngüsü kancasıdır. Bileşeninizin OnInitkullanabilmesi için uygulanması gerekir . Bu yaşam döngüsü kancası, yapıcı çağrıldıktan ve tüm değişkenler başlatıldıktan sonra çağrılır. Başlatma işleminizin büyük kısmı buraya gitmelidir. Angular'ın bileşeninizi doğru şekilde başlattığından emin olacaksınız ve bileşeniniz düzgün bir şekilde OnInityüklenmeyi bitirmediğinde bir şeyler yapmaya karşı ihtiyacınız olan herhangi bir mantığı yapmaya başlayabilirsiniz .

İşte denilen şeyin sırasını detaylandıran bir görüntü:

resim açıklamasını buraya girin

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

TLDR

Açısal 2 çerçevesini kullanıyorsanız ve belirli yaşam döngüsü olaylarıyla etkileşime girmeniz gerekiyorsa, sorunlardan kaçınmak için çerçeve tarafından sağlanan yöntemleri kullanın.


19

Bunu test etmek için, NativeScript Eğitimi'nden ödünç alarak bu kodu yazdım :

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

}

Konsol çıkışı

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

18

Yapıcı arasındaki temel fark ve ngOnInitolmasıdır ngOnInitolduğu yaşam döngüsü kanca ve yapıcı sonra çalışır. Bileşen enterpolasyonlu şablon ve giriş başlangıç ​​değerleri yapıcıda mevcut değildir, ancak içinde kullanılabilir ngOnInit.

Pratik fark, ngOnInitkodun nasıl yapılandırıldığını etkiler. Çoğu başlatma kodu taşınabilir ngOnInit- bu yarış koşulları yaratmaz sürece .

Oluşturucu antipattern

Önemli miktarda başlatma kodu, yapıcı yönteminin genişletilmesini, okunmasını ve test edilmesini zorlaştırır.

Başlatma mantığını sınıf yapıcısından ayırmak için olağan bir tarif, onu aşağıdaki gibi başka bir yönteme taşımaktır init:

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

  init() {...}
}

ngOnInit bileşenler ve direktiflerde bu amaca hizmet edebilir:

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

ngOnInit() {
  // rest of initialization code
}

Bağımlılık enjeksiyonu

Sınıf kurucularının Açısaldaki birincil rolü bağımlılık enjeksiyonudur. Yapıcılar ayrıca TypeScript'te DI notlaması için kullanılır. Hemen hemen tüm bağımlılıklar sınıf örneğine özellik olarak atanır.

Ortalama bileşen / yönerge kurucusu zaten yeterince büyük çünkü bağımlılıklar nedeniyle çok satırlı imzası olabilir, kurucu gövdeye gereksiz inisalizasyon mantığı koymak antipattern'e katkıda bulunur.

Eşzamansız başlatma

Asenkronize başlatma yapıcısı genellikle antipattern olarak kabul edilebilir ve kokusu olabilir çünkü sınıf instantiasyonu asenkron rutin olmadan önce biter ve bu yarış koşulları yaratabilir. Durum böyle değilse ngOnInitve diğer yaşam döngüsü kancaları bunun için daha iyi yerlerdir, özellikle asyncsözdiziminden yararlanabildikleri için :

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

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

Yarış koşulları varsa (bir bileşenin başlatma hatası sırasında görünmemesi gerekenler dahil), eşzamansız başlatma yordamı bileşen somutlaştırmadan önce gerçekleşmeli ve üst bileşene, yönlendirici korumasına vb. Taşınmalıdır.

Birim testi

ngOnInitbir kurucudan daha esnektir ve bu cevapta ayrıntılı olarak açıklanan birim testi için bazı faydalar sağlar .

ngOnInitBirim testlerinde bileşen derlemesinde otomatik olarak çağrılmadığı düşünüldüğünde, çağrılan yöntemler ngOnInitbileşen somutlaştırıldıktan sonra casusluk veya alay konusu yapılabilir.

İstisnai durumlarda ngOnInit, diğer bileşen birimleri (örneğin, bazı şablon mantığı) için yalıtım sağlamak üzere tamamen saplanabilir.

miras

Alt sınıflar yalnızca yapıcıları artırabilir, değiştiremez.

Daha thisönce atıfta bulunulmadığından super(), bu başlatma önceliğine kısıtlamalar getirir.

Açısal bileşen veya direktifin ngOnInitzamana duyarlı olmayan başlatma mantığı için kullanıldığını göz önünde bulundurarak , alt sınıflar super.ngOnInit()çağrılıp çağrılmayacağını ve ne zaman seçileceğini seçebilir :

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

Bunun sadece yapıcı ile uygulanması imkansızdır.


12

Yukarıdaki cevaplar asıl sorunun bu yönüne gerçekten cevap vermiyor: Yaşam döngüsü kancası nedir? Bu şekilde düşünene kadar bunun ne anlama geldiğini anlamam biraz zaman aldı.

1) Bileşeninizin bir insan olduğunu söyle. İnsanların yaşamın birçok aşamasını içeren yaşamları vardır ve sonra sona ereriz.

2) İnsan bileşenimiz aşağıdaki yaşam döngüsü komut dosyasına sahip olabilir: Doğan, Bebek, İlkokul, Genç Yetişkin, Orta Yaş Yetişkin, Kıdemli Yetişkin, Ölü, Bertaraf.

3) Çocuk oluşturma işlevine sahip olmak istediğinizi varsayalım. Bunun karmaşık ve oldukça mizahi olmasını önlemek için, işlevinizin yalnızca insan bileşen yaşamının Genç Yetişkin aşamasında çağrılmasını istiyorsunuz. Böylece, yalnızca ana bileşen Genç Yetişkin aşamasındayken aktif olan bir bileşen geliştirirsiniz. Kancalar, yaşamın bu aşamasını işaret ederek ve bileşeninizin üzerinde hareket etmesine izin vererek bunu yapmanıza yardımcı olur.

Eğlenceli şeyler. Hayal gücünüzün böyle bir şeyi kodlamaya gitmesine izin verirseniz, karmaşık ve komik olur.


7

Yapıcı JavaScript yöntemidir ve sınıf derhal o Açısal çerçevesinde kullanılıp kullanılmayacağını yapıcı çalıştırır veya JavaScript motoru tarafından çağrılır not.So ve Açısal hiçbir sahiptir örneği düşünüldüğünde kömür ES6 sınıf bir özelliği olarak kabul edilir üzerinde kontrol.

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

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

"ConstructorTest" sınıfı aşağıda örneklendirilmiştir; Bu nedenle dahili olarak yapıcıyı çağırır (Tüm bunlar JavaScript (es6) Açısal olmadan gerçekleşir).

new CONSTRUCTORTEST();

Bu nedenle Angular'de ngOnInit yaşam döngüsü kancası vardır. NgOnInit, Angular bileşeni başlatmayı tamamladığında oluşturulur.

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

İlk olarak derhal yapıcı yönteminin derhal çalıştırıldığı sınıfı başlatırız.

let instance = new NGONINITTEST();

ngOnInit gerektiğinde Angular tarafından aşağıdaki gibi çağrılır:

instance.ngOnInit();

Ama neden Angular'da yapıcı kullandığımızı sorabilirsiniz?

Yanıt bağımlılık enjeksiyonlarıdır . Daha önce de belirtildiği gibi, derleyici derlendiğinde derhal JavaScript motoru tarafından çağrı yapar (ngOnInit'i Açısal olarak çağırmadan önce), bu yüzden daktilo türü yapıcıda tanımlanmış bağımlılıkların türünü almamıza yardımcı olur ve son olarak söyler Söz konusu bileşende ne tür bağımlılıklar kullanmak istediğimizi açısal olarak belirler.


7

Burada gözlemlenmesi gereken iki şey:

  1. Bu sınıftan bir nesne oluşturulduğunda yapıcı çağrılır.
  2. Bileşen oluşturulduktan sonra ngOnInit çağrılır.

Her ikisinin de farklı kullanılabilirliği vardır.


5

constructor () , Bileşen yaşam döngüsünde varsayılan yöntemdir ve bağımlılık enjeksiyonu için kullanılır. Yapıcı bir Daktilo Yazısı Özelliğidir.

ngOnInit () yapıcıdan sonra çağrılır ve ngOnInit ilk ngOnChanges'den sonra çağrılır.

yani:

Yapıcı () -->ngOnChanges () -->ngOnInit ()

yukarıda belirtildiği gibi ngOnChanges()bir girdi veya çıktı bağlama değeri değiştiğinde çağrılır.


4

Her iki yöntemin de farklı hedefleri / sorumlulukları vardır. Yapıcı (dil destekli bir özelliktir) görevi, temsil değişmezinin sahip olduğundan emin olmaktır. Aksi takdirde, üyeye doğru değerler vererek örneğin geçerli olduğundan emin olmak için belirtilir. 'Doğru' ifadesinin ne anlama geldiğine karar vermek geliştiriciye bağlıdır.

OnInit () yönteminin (açısal bir kavramdır) görevi, doğru bir nesne (temsil değişmezi) üzerinde yöntem çağırmalarına izin vermektir. Her yöntem de, yöntem sona erdiğinde temsil değişmezinin tutulduğundan emin olmalıdır.

Yapıcı 'doğru' nesneler oluşturmak için kullanılmalıdır, onInit yöntemi size iyi tanımlanmış bir örnekte yöntem çağrılarını çağırma fırsatı verir.


4

Yapıcı: ES6 sınıfındaki (veya bu durumda TypeScript) yapıcı yöntemi, Açısal özellik yerine sınıfın kendisinin bir özelliğidir. Yapıcı çağrıldığında Angular'ın kontrolü dışındadır, yani Angular bileşeni başlatmayı bitirdiğinizde size bildirmek için uygun bir kanca olmadığı anlamına gelir. JavaScript motoru, doğrudan Açısal değil yapıcıyı çağırır. Bu nedenle ngOnInit (ve AngularJS'de $ onInit) yaşam döngüsü kancası oluşturuldu. Bunu göz önünde bulundurarak, yapıcıyı kullanmak için uygun bir senaryo vardır. Bu, bağımlılık enjeksiyonunu kullanmak istediğimizde - esas olarak bileşene bağımlılıkları “bağlamak” için.

Yapıcı JavaScript motoru tarafından başlatıldığından ve TypeScript, Angular'a belirli bir özelliğe karşı eşleştirilmemiz gereken bağımlılıkları söylememizi sağlar.

ngOnInit , Angular'ın bileşeni başlatmayı tamamladığını bize bildirmek için tamamen oradadır.

Bu aşama, @Input () dekoratörü kullanmak gibi, bileşenin kendisine bağlayabileceğimiz özelliklere karşı Değişiklik Algılama'daki ilk geçişi içerir.

Bu nedenle, @Input () özellikleri ngOnInit içinde kullanılabilir, ancak tasarım gereği kurucu içinde tanımlanmamıştır


2

Birincisi yapıcıdır ve bazen @input verileri null olduğunda olur! bu nedenle Hizmetleri bildirmek için Yapıcı kullanırız ve ngOnInit sonra olur. Kontrolör için örnek:

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

OnInit için örnek:

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

Ben onInit winForm InitialComponents () gibi olduğunu düşünüyorum.


1

Açısal yaşam döngülerinde

1) Açısal enjektör, yapıcı parametresini (parametrelerini) ve örnek sınıfı algılar.

2) Sonraki açısal çağrı yaşam döngüsü

Açısal Yaşam Döngüsü Kancaları

ngOnChanges -> Direktif parametrelerine bağlanma çağrısı.

ngOnInit -> Açısal oluşturmayı başlat ...

Açısal yaşam döngüsü durumuna sahip diğer yöntemi çağırın.


1

constructorZaman Açısal "instanciates / yapılar" bileşeni denir. ngOnInitYöntem, bileşen ömrünün başlatma bölümüdür bir kancadır. İyi bir uygulama, sadece servis enjeksiyonu için kullanmaktır :

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

Mümkün olsa bile, içeride “iş” yapmamalısınız. "Başlatma" bileşeninde gerçekleşmesi gereken bazı eylemleri başlatmak istiyorsanız, şunu kullanın ngOnInit:

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

Ayrıca, bir üst bileşenden gelen girdi özelliklerini içeren eylemler yapıcıda gerçekleştirilemez. ngOnInitYöntem veya başka bir kancaya yerleştirilmelidirler . Görünümle (DOM) ilgili öğe, örneğin görünüm penceresi öğeleri için aynıdır :

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

0

constructor() bağımlılık enjeksiyonu yapmak için kullanılır.

ngOnInit(), ngOnChanges()Ve ngOnDestroy()vb yaşam döngüsü yöntemlerdir. bir bağlı özelliğin değeri değiştiğinde ngOnChanges()önce çağrılacak ilk kişi olur, ngOnInit()değişiklik yoksa çağrılmaz. ngOnDestroy()bileşen kaldırıldığında çağrılır. Kullanmak için sınıf tarafından düzenlenmesi OnDestroygerekir implement.


1
katılıyorum, bu kısa ve açık. Örneğin, yapıcı () servis nesneleri eklemek içindir, ngOnInit () gerekli servis fonksiyonu çağrılarıyla bileşenleri değiştirmek içindir.
Steve

0

Cevabı buldum ve İngilizce'ye çevirmeye çalıştım: Bu soru, teknik görüşmelerde bile hala ortaya çıktı. Aslında, ikisi arasında büyük bir benzerlik var, ancak bazı farklılıklar da var.

  • Yapıcı ECMAScript'in bir parçasıdır. Diğer yandan ngOnInit (), açısal bir kavramdır.

  • Açısal kullanmasak bile tüm sınıflardaki yapıcıları çağırabiliriz

  • LifeCycle: Yapıcı ngOnInt () öncesi çağrılır

  • Yapıcıda HTML öğelerini çağıramayız. Ancak, ngOnInit () 'de yapabiliriz.

  • Genellikle, yapıcıda değil, ngOnInit () 'deki servis çağrıları

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


0

inşaatçı

Yapıcı işlevi her sınıfla birlikte gelir, yapıcılar Açısal'a özgü değildir, ancak Nesne yönelimli tasarımlardan türetilen kavramlardır. Yapıcı, bileşen sınıfının bir örneğini oluşturur.

OnInit

ngOnInitİşlev Açısal bileşenin yaşam döngüsü yöntemlerden biridir. Açısal bileşenlerdeki yaşam döngüsü yöntemleri (veya kancaları), bir bileşenin ömrünün farklı aşamalarında bir kod parçası çalıştırmanıza olanak tanır. Yapıcı yönteminden farklı olarak, yöntem, bileşenin bu yöntemi kullanmak için uygulaması gereken ngOnInitbir Açısal arabirimden ( OnInit) gelir. ngOnInitBileşen oluşturulduktan sonra yöntem kısaca denir.


0

Oluşturucu sınıf somutlaştırıldığında yürütülür. Açısal ile hiçbir ilgisi yok. Javascript özelliğidir ve Angular üzerinde kontrol sahibi değildir

NgOnInit Açısal özeldir ve Açısal bileşeni tüm girdi özellikleriyle başlattığında çağrılır

@Input özellikleri ngOnInit yaşam döngüsü kancasının altında bulunur. Bu, görünümde görüntülenmesi için arka uç sunucusundan veri alma vb.

@Input özellikleri yapıcı içinde tanımsız olarak gösterilir


-1

Yapıcı , bileşen (veya başka bir sınıf) oluşturulduğunda yürütülen bir işlevdir.

ngOnInit , bileşen yaşam döngüsü yöntem gruplarına ait bir işlevdir ve bileşenimizin farklı bir anında yürütülür (bu nedenle yaşam döngüsü adı verilir). İşte hepsinin bir listesi:

resim açıklamasını buraya girin Yapıcı, herhangi bir yaşam döngüsü işlevinden önce yürütülecektir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.