เชิงมุมให้เบ็ดวงจรชีวิตngOnInit
โดยค่าเริ่มต้น
ทำไมngOnInit
ต้องใช้ถ้าเรามีconstructor
?
เชิงมุมให้เบ็ดวงจรชีวิตngOnInit
โดยค่าเริ่มต้น
ทำไมngOnInit
ต้องใช้ถ้าเรามีconstructor
?
คำตอบ:
Constructor
เป็นวิธีการเริ่มต้นของการเรียนที่มีการดำเนินการเมื่อชั้นถูกสร้างและสร้างความมั่นใจ initialisation ที่เหมาะสมของเขตข้อมูลในชั้นเรียนและ subclasses ของมัน Angular หรือดีกว่า Dependency Injector (DI) วิเคราะห์พารามิเตอร์ Constructor และเมื่อมันสร้างอินสแตนซ์ใหม่โดยการเรียกnew MyClass()
มันจะพยายามค้นหาผู้ให้บริการที่ตรงกับประเภทของพารามิเตอร์ Constructor แก้ไขพวกมันและส่งมันไปยัง Constructor เช่น
new MyClass(someArg);
ngOnInit
เป็นตะขอวงจรชีวิตที่เรียกโดย Angular เพื่อบ่งชี้ว่า Angular เสร็จสิ้นการสร้างส่วนประกอบ
เราต้องนำเข้าOnInit
เช่นนี้เพื่อใช้งาน (การใช้งานจริงOnInit
ไม่บังคับ แต่ถือเป็นการปฏิบัติที่ดี):
import { Component, OnInit } from '@angular/core';
จากนั้นจะใช้ทำให้เราเป็นวิธีOnInit
เราต้องใช้คลาสเช่นนี้:
export class App implements OnInit {
constructor() {
// Called first time before the ngOnInit()
}
ngOnInit() {
// Called after the constructor and called after the first ngOnChanges()
}
}
ใช้อินเทอร์เฟซนี้เพื่อดำเนินการตรรกะการเริ่มต้นที่กำหนดเองหลังจากคุณสมบัติขอบเขตข้อมูลของคำสั่งของคุณได้รับการเริ่มต้น ngOnInit ถูกเรียกใช้ทันทีหลังจากตรวจสอบคุณสมบัติขอบเขตข้อมูลของคำสั่งเป็นครั้งแรกและก่อนที่จะมีการตรวจสอบลูก ๆ มันถูกเรียกเพียงครั้งเดียวเมื่อสั่งถูกยกตัวอย่าง
ส่วนใหญ่เราใช้ngOnInit
สำหรับการเริ่มต้น / ประกาศทั้งหมดและหลีกเลี่ยงสิ่งที่จะทำงานในตัวสร้าง ตัวสร้างควรใช้เพื่อเริ่มต้นสมาชิกคลาส แต่ไม่ควร "ทำงาน" จริง
ดังนั้นคุณควรใช้constructor()
การตั้งค่าการฉีดพึ่งพาและไม่มาก ngOnInit () เป็นสถานที่ที่ดีกว่าในการ "เริ่มต้น" - เป็นที่ / เมื่อการผูกส่วนประกอบได้รับการแก้ไข
สำหรับข้อมูลเพิ่มเติมอ้างอิงที่นี่:
tsconfig.json
ไฟล์เช่น"strict": true
นั้นคุณจะต้องเริ่มต้นสมาชิกชั้นในconstructor
ไม่ได้อยู่ในเช่นngOnit
FormGroup
บทความความแตกต่างที่สำคัญระหว่าง Constructor และ ngOnInit ใน Angularสำรวจความแตกต่างจากหลายมุมมอง คำตอบนี้ให้คำอธิบายความแตกต่างที่สำคัญที่สุดที่เกี่ยวข้องกับกระบวนการกำหนดค่าเริ่มต้นขององค์ประกอบซึ่งแสดงการใช้งานที่แตกต่างกัน
กระบวนการบูทสแตรปแบบ Angular ประกอบด้วยสองขั้นตอนหลัก:
ตัวสร้างของส่วนประกอบถูกเรียกเมื่อทรีแองกูลาร์สร้างส่วนประกอบของต้นไม้ ตะขอวงจรชีวิตทั้งหมดเรียกว่าเป็นส่วนหนึ่งของการตรวจจับการเปลี่ยนแปลงการเรียกใช้
เมื่อแองกูลาร์สร้างส่วนประกอบต้นไม้โมดูลรูทของหัวฉีดได้รับการกำหนดค่าไว้แล้วเพื่อให้คุณสามารถฉีดการพึ่งพาทั่วโลก นอกจากนี้เมื่อ Angular สร้างอินสแตนซ์คลาสของคอมโพเนนต์ลูกอินเจ็คเตอร์สำหรับคอมโพเนนต์พาเรนต์ก็ตั้งค่าไว้แล้วดังนั้นคุณจึงสามารถฉีดผู้ให้บริการที่กำหนดไว้ในคอมโพเนนต์หลักรวมถึงองค์ประกอบหลักเอง ตัวสร้างส่วนประกอบเป็นวิธีการเดียวที่เรียกว่าในบริบทของหัวฉีดดังนั้นหากคุณต้องการการพึ่งพาใด ๆ นั่นเป็นเพียงที่เดียวที่จะได้รับการอ้างอิงเหล่านั้น
เมื่อ Angular เริ่มเปลี่ยนการตรวจจับต้นไม้ส่วนประกอบจะถูกสร้างขึ้นและตัวสร้างสำหรับส่วนประกอบทั้งหมดในต้นไม้ได้ถูกเรียก นอกจากนี้ยังมีส่วนประกอบของทุกโหนดแม่แบบจะมีการเพิ่ม DOM @Input
กลไกการสื่อสารมีการประมวลผลในระหว่างการตรวจสอบการเปลี่ยนแปลงเพื่อให้คุณไม่สามารถคาดหวังที่จะมีคุณสมบัติที่มีอยู่ในตัวสร้าง ngOnInit
มันจะมีอยู่บนหลัง
มาดูตัวอย่างด่วน สมมติว่าคุณมีเทมเพลตต่อไปนี้:
<my-app>
<child-comp [i]='prop'>
ดังนั้น Angular เริ่มการบูตแอปพลิเคชัน ที่ผมกล่าวว่ามันเป็นครั้งแรกสร้างชั้นเรียนสำหรับแต่ละองค์ประกอบ ดังนั้นมันจึงเรียกคอนMyAppComponent
สตรัคเตอร์ นอกจากนี้ยังสร้างโหนด DOM ซึ่งเป็นองค์ประกอบโฮสต์ของmy-app
องค์ประกอบ จากนั้นจะดำเนินการสร้างองค์ประกอบโฮสต์สำหรับchild-comp
และเรียกคอนChildComponent
สตรัค ในขั้นตอนนี้ไม่เกี่ยวข้องกับการi
เชื่อมโยงอินพุตและวงจรชีวิตใด ๆ ดังนั้นเมื่อกระบวนการนี้เสร็จสิ้น Angular จะจบลงด้วยทรีของมุมมองคอมโพเนนต์ต่อไปนี้:
MyAppView
- MyApp component instance
- my-app host element data
ChildCompnentView
- ChildComponent component instance
- child-comp host element data
จากนั้นเรียกใช้การตรวจจับการเปลี่ยนแปลงและอัปเดตการเชื่อมโยงสำหรับmy-app
และการโทรngOnInit
บนคลาส MyAppComponent จากนั้นจะดำเนินการอัพเดตการเชื่อมโยงสำหรับchild-comp
และเรียกngOnInit
ใช้คลาส ChildComponent
คุณสามารถทำตรรกะของคุณเริ่มต้นในตัวสร้างหรือngOnInit
ขึ้นอยู่กับสิ่งที่คุณต้องการใช้ได้ ตัวอย่างบทความนี่คือวิธีการรับ ViewContainerRef ก่อนการประเมิน @ViewChild แบบสอบถามแสดงประเภทของตรรกะการเริ่มต้นที่จะต้องดำเนินการในตัวสร้าง
นี่คือบทความบางส่วนที่จะช่วยให้คุณเข้าใจหัวข้อได้ดีขึ้น:
the constructor should only be used to inject dependencies
มันจริงอธิบายทำไมมากกว่าการทำซ้ำมนต์และเซน
ฉันคิดว่าตัวอย่างที่ดีที่สุดคือการใช้บริการ สมมติว่าฉันต้องการคว้าข้อมูลจากเซิร์ฟเวอร์ของฉันเมื่อส่วนประกอบของฉันได้รับ 'เปิดใช้งาน' สมมติว่าฉันต้องการทำสิ่งเพิ่มเติมบางอย่างกับข้อมูลหลังจากที่ฉันได้รับจากเซิร์ฟเวอร์บางทีฉันอาจได้รับข้อผิดพลาดและต้องการเข้าสู่ระบบที่แตกต่างกัน
มันง่ายมากที่จะมี ngOnInit ผ่าน Constructor และมันก็ จำกัด จำนวนการโทรกลับของเลเยอร์ที่ฉันต้องการเพิ่มลงในแอปพลิเคชันของฉัน
ตัวอย่างเช่น:
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);
};
}
กับ constructor ของฉันฉันสามารถโทรหาผู้ใช้ _userService ของฉันและเติม user_list ของฉันได้ แต่บางทีฉันอาจต้องการทำสิ่งพิเศษบางอย่างกับมัน เช่นเดียวกับตรวจสอบให้แน่ใจว่าทุกอย่างเป็น upper_case ฉันไม่แน่ใจว่าข้อมูลของฉันจะผ่านมาอย่างไร
ดังนั้นจึงทำให้การใช้ 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();
};
}
มันทำให้มองเห็นได้ง่ายขึ้นและดังนั้นฉันจึงเรียกฟังก์ชันของฉันในองค์ประกอบของฉันเมื่อฉันเริ่มต้นแทนที่จะต้องขุดหาที่อื่น จริงๆแล้วเป็นเพียงเครื่องมืออีกอย่างที่คุณสามารถใช้เพื่อให้อ่านและใช้งานได้ง่ายขึ้นในอนาคต นอกจากนี้ฉันคิดว่ามันเป็นการปฏิบัติที่ไม่ดีจริงๆที่จะนำการเรียกใช้ฟังก์ชันภายในตัวสร้าง!
getUsers
ก่อนแล้วจึงใส่มันเข้าไปngOnInit
? มันไม่น้อยรหัสที่จะเขียนใน ngOnInit? ฉันกำลังสงสัยว่าทำไมผู้คนถึงทำแบบนี้? เป็นเช่นนั้นหรือไม่หากคุณต้องการใช้รหัสซ้ำอีกครั้ง ขอบคุณ
constructor
?
constructor(private _userService: UserService){ this.getUsers(); };
ตกลงก่อนอื่นngOnInit
เป็นส่วนหนึ่งของวงจรชีวิตเชิงมุมในขณะที่constructor
เป็นส่วนหนึ่งของคลาสES6 JavaScript ดังนั้นความแตกต่างที่สำคัญเริ่มต้นที่นี่! ...
ดูแผนภูมิด้านล่างที่ฉันสร้างซึ่งแสดงวงจรชีวิตของ Angular
ใน Angular2 + เราใช้constructor
ในการทำDI(Dependency Injection)
เพื่อเราในขณะที่ Angular 1 มันเกิดขึ้นผ่านการโทรไปยังวิธีการ String และตรวจสอบว่าการพึ่งพาใดถูกฉีด
ดังที่คุณเห็นในแผนภาพด้านบนngOnInit
เกิดขึ้นหลังจากตัวสร้างพร้อมและngOnChnages
ถูกไล่ออกหลังจากส่วนประกอบพร้อมสำหรับเรา การเริ่มต้นทั้งหมดสามารถเกิดขึ้นได้ในขั้นตอนนี้ตัวอย่างง่ายๆคือการฉีดเซอร์วิสและเริ่มต้นด้วย init
ตกลงฉันยังแชร์รหัสตัวอย่างเพื่อให้คุณดูดูวิธีการใช้ngOnInit
และconstructor
รหัสด้านล่าง:
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!');
}
}
คนแรก (คอนสตรัคเตอร์) เกี่ยวข้องกับอินสแตนซ์ของคลาสและไม่มีส่วนเกี่ยวข้องกับ Angular2 ฉันหมายถึงคอนสตรัคเตอร์สามารถใช้กับคลาสใดก็ได้ คุณสามารถใส่การประมวลผลเริ่มต้นสำหรับอินสแตนซ์ที่สร้างขึ้นใหม่ได้
อันที่สองสอดคล้องกับวงจรชีวิตของส่วนประกอบของ Angular2:
อ้างถึงจากเว็บไซต์อย่างเป็นทางการของเชิงมุม:
ngOnChanges
ถูกเรียกเมื่อมีการเปลี่ยนแปลงค่าการเชื่อมโยงอินพุตหรือเอาต์พุตngOnInit
ถูกเรียกหลังจากครั้งแรกngOnChanges
ดังนั้นคุณควรใช้ngOnInit
หากการประมวลผลเริ่มต้นขึ้นอยู่กับการผูกของส่วนประกอบ (ตัวอย่างเช่นพารามิเตอร์องค์ประกอบที่กำหนดด้วย@Input
) มิฉะนั้นตัวสร้างจะเพียงพอ ...
ฉันเพิ่งจะเพิ่มสิ่งหนึ่งที่สำคัญที่ถูกข้ามไปในคำอธิบายข้างต้นและอธิบายเมื่อคุณต้องngOnInit
ใช้
หากคุณทำการจัดการ DOM ขององค์ประกอบผ่านทางViewChildren , ContentChildrenหรือElementRefองค์ประกอบดั้งเดิมของคุณจะไม่สามารถใช้ได้ในช่วงตัวสร้าง
อย่างไรก็ตามเนื่องจากngOnInit
เกิดขึ้นเมื่อองค์ประกอบถูกสร้างขึ้นและการตรวจสอบ ( ngOnChanges
) ได้รับการเรียกว่าคุณสามารถเข้าถึง DOM ที่จุดนี้
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
}
}
@ViewChildren
โดยเฉพาะอย่างยิ่งที่คุณจำเป็นต้องใช้ngAfterViewInit
วิธีการ ดูที่นี่: stackoverflow.com/questions/46314734/…
คำตอบที่สั้นและง่ายจะเป็น
Constructor
: constructor
is a default method
run ( โดย deafult ) เมื่อมีการสร้างส่วนประกอบ เมื่อคุณสร้างan instance
ชั้นเรียนในเวลานั้นก็constructor(default method)
จะถูกเรียกว่า ดังนั้นในคำอื่น ๆ เมื่อองค์ประกอบจะถูกconstructed or/and an instance is created constructor(default method)
เรียกและรหัสที่เกี่ยวข้องภายในถูกเรียกว่า โดยทั่วไปและโดยทั่วไปAngular2
จะใช้ในการฉีดสิ่งต่าง ๆ เช่นservices
เมื่อมีการสร้างส่วนประกอบสำหรับการใช้งานเพิ่มเติม
OnInit
: ngOnInit เป็นเบ็ดวงจรชีวิตของส่วนประกอบที่ทำงานครั้งแรกหลังจากที่constructor(default method)
เมื่อองค์ประกอบจะถูกเริ่มต้น
ดังนั้น Constructor ของคุณจะถูกเรียกก่อนและ Oninit จะถูกเรียกในภายหลังหลังจาก Constructor Method
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()
}
}
ทรัพยากร: LifeCycle hook
คุณสามารถตรวจสอบการสาธิตขนาดเล็กนี้ซึ่งแสดงให้เห็นถึงการใช้งานของทั้งสองสิ่ง
new MyClass()
การเรียกใช้รหัสเช่น ฉันคิดว่ามันเป็นความเข้าใจผิดที่จะบอกว่าคอนสตรัคเตอร์นั้นเกี่ยวกับส่วนประกอบพวกมันเกี่ยวกับคลาสและการเริ่มต้นอินสแตนซ์ของคลาสเหล่านี้ ส่วนประกอบเกิดขึ้นเป็นคลาสดังกล่าว มิฉะนั้นฉันคิดว่ามันเป็นคำตอบที่ดี
constructor
จะถูกเรียกว่า แต่คำตอบนี้เขียนขึ้นในบริบทของ angular2 หากต้องการทราบคำตอบที่ดีที่สุดคุณจะต้องรู้พื้นฐานของ OOP ยังฉันจะอัปเดตคำตอบ
เช่นเดียวกับภาษาอื่น ๆ มากมายคุณสามารถกำหนดค่าเริ่มต้นของตัวแปรที่ระดับคลาสตัวสร้างหรือเมธอด ขึ้นอยู่กับผู้พัฒนาที่จะตัดสินใจว่าอะไรดีที่สุดในกรณีของพวกเขา แต่ด้านล่างเป็นรายการแนวทางปฏิบัติที่ดีที่สุดเมื่อต้องตัดสินใจ
โดยปกติแล้วคุณจะประกาศตัวแปรทั้งหมดของคุณที่นี่ซึ่งจะถูกใช้ในองค์ประกอบที่เหลือของคุณ คุณสามารถเริ่มต้นได้หากค่าไม่ได้ขึ้นอยู่กับสิ่งอื่นหรือใช้คำหลัก const เพื่อสร้างค่าคงที่หากพวกเขาจะไม่เปลี่ยนแปลง
export class TestClass{
let varA: string = "hello";
}
โดยปกติแล้วมันเป็นแนวปฏิบัติที่ดีที่สุดที่จะไม่ทำอะไรเลยในนวกรรมิกและใช้สำหรับคลาสที่จะถูกฉีด ส่วนใหญ่คอนสตรัคของคุณควรมีลักษณะเช่นนี้:
constructor(private http: Http, private customService: CustomService) {}
สิ่งนี้จะสร้างตัวแปรระดับชั้นเรียนโดยอัตโนมัติดังนั้นคุณจะสามารถเข้าถึงได้customService.myMethod()
โดยไม่ต้องทำด้วยตนเอง
NgOnit เป็น lifecycle hook ที่จัดทำโดย Angular 2 framework ส่วนประกอบของคุณจะต้องใช้งานOnInit
เพื่อที่จะใช้มัน วงจรชีวิตของ hook นี้ถูกเรียกหลังจากคอนสตรัคเตอร์ถูกเรียกใช้และตัวแปรทั้งหมดจะเริ่มต้นได้ ส่วนใหญ่ของการเริ่มต้นของคุณควรไปที่นี่ คุณจะมีความมั่นใจว่า Angular ได้เริ่มต้นองค์ประกอบของคุณอย่างถูกต้องและคุณสามารถเริ่มทำตรรกะใด ๆ ที่คุณต้องการOnInit
เมื่อเทียบกับการทำสิ่งต่าง ๆ เมื่อส่วนประกอบของคุณโหลดไม่เสร็จ
นี่คือภาพที่แสดงลำดับของสิ่งที่ถูกเรียก:
https://angular.io/docs/ts/latest/guide/lifecycle-hooks.html
หากคุณกำลังใช้เฟรมเวิร์ก Angular 2 และต้องการโต้ตอบกับเหตุการณ์รอบระยะเวลาหนึ่งให้ใช้วิธีการที่กำหนดโดยเฟรมเวิร์กสำหรับสิ่งนี้เพื่อหลีกเลี่ยงปัญหา
เพื่อทดสอบสิ่งนี้ฉันเขียนโค้ดนี้โดยขอยืมมาจากการสอน 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;
}
}
เอาต์พุตคอนโซล
JS: *** User class constructor property ***
JS: *** User class constructor constructor ***
JS: *** Login Component Constructor ***
JS: *** User class constructor ngOnInit ***
JS: *** Login Component ngOnInit ***
ข้อแตกต่างที่สำคัญระหว่าง Constructor และngOnInit
นั่นngOnInit
คือLifecycle Hookและวิ่งตาม Constructor แม่แบบหยันตัวแทนและใส่ค่าเริ่มต้นจะไม่สามารถใช้ได้ในตัวสร้าง ngOnInit
แต่พวกเขาอยู่ในที่มีอยู่
ความแตกต่างในทางปฏิบัติคือngOnInit
ผลกระทบต่อวิธีการจัดโครงสร้างของโค้ดอย่างไร รหัสเริ่มต้นส่วนใหญ่สามารถย้ายไปngOnInit
- ตราบใดที่นี้ไม่ได้สร้างเงื่อนไขการแข่งขัน
รหัสเริ่มต้นจำนวนมากทำให้วิธีการสร้างยากที่จะขยายอ่านและทดสอบ
สูตรปกติสำหรับการแยกตรรกะการเริ่มต้นจากตัวสร้างคลาสคือการย้ายไปยังวิธีอื่นเช่นinit
:
class Some {
constructor() {
this.init();
}
init() {...}
}
ngOnInit
สามารถตอบสนองวัตถุประสงค์นี้ในองค์ประกอบและคำสั่ง:
constructor(
public foo: Foo,
/* verbose list of dependencies */
) {
// time-sensitive initialization code
this.bar = foo.getBar();
}
ngOnInit() {
// rest of initialization code
}
บทบาทหลักของตัวสร้างคลาสในเชิงมุมคือการฉีดแบบพึ่งพา ตัวสร้างยังใช้สำหรับคำอธิบายประกอบ DI ใน TypeScript การอ้างอิงเกือบทั้งหมดถูกกำหนดเป็นคุณสมบัติให้กับอินสแตนซ์ของคลาส
ค่าเฉลี่ยคอนสตรัคเตอร์ / ไดเรกทีฟไดเร็กต์มีขนาดใหญ่พอเนื่องจากสามารถมีลายเซ็นแบบหลายบรรทัดเนื่องจากการอ้างอิงทำให้การสร้างลอจิกแบบไม่จำเป็นไปยังตัวสร้างคอนสตรัคชันมีส่วนต่อ antipattern
ตัวสร้างการเริ่มต้นแบบอะซิงโครนัสสามารถพิจารณา antipattern และมีกลิ่นได้เนื่องจากการสร้างอินสแตนซ์ของคลาสเสร็จสิ้นก่อนรูทีนแบบอะซิงโครนัสทำและสิ่งนี้สามารถสร้างเงื่อนไขการแข่งขันได้ หากไม่ใช่กรณีดังกล่าวngOnInit
และขอวงจรชีวิตอื่น ๆ เป็นสถานที่ที่ดีกว่าสำหรับเรื่องนี้โดยเฉพาะอย่างยิ่งเพราะพวกเขาสามารถได้รับประโยชน์จากasync
ไวยากรณ์:
constructor(
public foo: Foo,
public errorHandler: ErrorHandler
) {}
async ngOnInit() {
try {
await this.foo.getBar();
await this.foo.getBazThatDependsOnBar();
} catch (err) {
this.errorHandler.handleError(err);
}
}
หากมีสภาพการแข่งขัน (รวมถึงองค์ประกอบที่ไม่ควรปรากฏบนข้อผิดพลาดในการเริ่มต้น) ขั้นตอนการเริ่มต้นแบบอะซิงโครนัสควรเกิดขึ้นก่อนการเริ่มต้นส่วนประกอบและถูกย้ายไปยังองค์ประกอบหลัก, เราเตอร์เป็นต้น
ngOnInit
มีความยืดหยุ่นมากกว่าตัวสร้างและให้ประโยชน์บางอย่างสำหรับการทดสอบหน่วยที่อธิบายรายละเอียดในคำตอบนี้
เมื่อพิจารณาว่าไม่ได้ngOnInit
ถูกเรียกโดยอัตโนมัติในการรวบรวมส่วนประกอบในการทดสอบหน่วยวิธีการที่เรียกใช้ในngOnInit
นั้นสามารถถูกสอดแนมหรือเยาะเย้ยหลังจากการเริ่มต้นส่วนประกอบ
ในกรณีที่ยอดเยี่ยมngOnInit
สามารถถูก stubbed ทั้งหมดเพื่อให้แยกสำหรับหน่วยส่วนประกอบอื่น ๆ (เช่นตรรกะบางแม่แบบ)
ชั้นเรียนของเด็กสามารถเพิ่ม Constructor เท่านั้นไม่สามารถแทนที่ได้
เนื่องจากthis
ไม่สามารถอ้างถึงก่อนหน้าsuper()
นี้ได้ทำให้มีข้อ จำกัด ในการเริ่มต้น
เมื่อพิจารณาว่าองค์ประกอบเชิงมุมหรือการใช้คำสั่งngOnInit
สำหรับตรรกะการกำหนดค่าเริ่มต้นที่ไม่คำนึงถึงเวลาคลาสเด็กสามารถเลือกได้ว่าsuper.ngOnInit()
จะเรียกและเมื่อ:
ngOnInit() {
this.someMethod();
super.ngOnInit();
}
สิ่งนี้คงเป็นไปไม่ได้ที่จะนำไปใช้กับคอนสตรัคเตอร์เพียงอย่างเดียว
คำตอบข้างต้นไม่ได้ตอบคำถามในแง่มุมดั้งเดิมของคำถามนี้: วงจรชีวิตคืออะไร? ฉันใช้เวลาสักครู่เพื่อทำความเข้าใจความหมายจนกว่าฉันจะคิดแบบนี้
1) องค์ประกอบของคุณเป็นมนุษย์ มนุษย์มีชีวิตที่มีหลายขั้นตอนแล้วเราก็หมดอายุ
2) องค์ประกอบของมนุษย์ของเราสามารถมีวงจรชีวิตสคริปต์ต่อไปนี้: เกิด, เด็ก, โรงเรียนเกรด, ผู้ใหญ่, ผู้ใหญ่วัยกลางคน, ผู้ใหญ่อาวุโส, ตาย, ถูกกำจัด
3) สมมติว่าคุณต้องการมีฟังก์ชั่นในการสร้างลูก เพื่อป้องกันไม่ให้สิ่งนี้มีความซับซ้อนและค่อนข้างตลกขบขันคุณต้องการให้งานของคุณถูกเรียกเฉพาะในช่วงวัยผู้ใหญ่ของชีวิตองค์ประกอบมนุษย์ ดังนั้นคุณจึงพัฒนาส่วนประกอบที่ใช้งานได้ก็ต่อเมื่อองค์ประกอบหลักอยู่ในช่วงวัยผู้ใหญ่ hooks ช่วยให้คุณทำเช่นนั้นได้ด้วยการส่งสัญญาณช่วงเวลาแห่งชีวิตและปล่อยให้องค์ประกอบของคุณทำตาม
สิ่งที่สนุก. ถ้าคุณปล่อยให้จินตนาการของคุณไปเขียนโค้ดแบบนี้มันจะซับซ้อนและตลก
ตัวสร้างเป็นวิธีการใน JavaScript และถือเป็นคุณสมบัติของคลาสใน es6 เมื่อชั้นถูกสร้างอินสแตนซ์มันทันทีเรียกใช้ตัวสร้างไม่ว่าจะใช้ในกรอบ Angular หรือไม่ดังนั้นมันถูกเรียกโดยเครื่องมือ JavaScript และ Angular ไม่มี ควบคุมว่า
import {Component} from '@angular/core';
@Component({})
class CONSTRUCTORTEST {
//This is called by Javascript not the Angular.
constructor(){
console.log("view constructor initialised");
}
}
คลาส "ConstructorTest" มีการสร้างอินสแตนซ์ด้านล่างดังนั้นจึงเรียกภายในตัวสร้าง (ทั้งหมดนี้เกิดขึ้นโดย JavaScript (es6) ไม่มีแองกูลาร์)
new CONSTRUCTORTEST();
ด้วยเหตุนี้จึงมีตะขอวงจรชีวิตngOnInitใน Angular.ngOnInit แสดงผลเมื่อ Angular เสร็จสิ้นการเริ่มต้นส่วนประกอบ
import {Component} from '@angular/core';
@Component({})
class NGONINITTEST implements onInit{
constructor(){}
//ngOnInit calls by Angular
ngOnInit(){
console.log("Testing ngOnInit");
}
}
ก่อนอื่นเราจะยกตัวอย่างคลาสดังต่อไปนี้ซึ่งเกิดขึ้นกับการรันของเมธอด constructor ทันที
let instance = new NGONINITTEST();
ngOnInit ถูกเรียกใช้โดย Angular เมื่อจำเป็นดังต่อไปนี้:
instance.ngOnInit();
แต่คุณอาจถามว่าทำไมเราถึงใช้ตัวสร้างใน Angular
คำตอบคือการพึ่งพาการฉีดตามที่ได้กล่าวไว้ก่อนการเรียก constructor โดยเครื่องมือ JavaScript ทันทีเมื่อคลาสนั้นถูกสร้างอินสแตนซ์ (ก่อนที่จะเรียก ngOnInit โดย Angular) ดังนั้น typescript จะช่วยให้เราได้ชนิดของการพึ่งพาที่กำหนดไว้ในนวกรรมิก ชนิดของการพึ่งพาที่เราต้องการใช้ในองค์ประกอบเฉพาะนั้น
สองสิ่งที่ควรสังเกตที่นี่:
ทั้งสองมีการใช้งานที่แตกต่างกัน
นวกรรมิก ()เป็นวิธีการเริ่มต้นในวงจรชีวิตส่วนประกอบและใช้สำหรับการฉีดพึ่งพา ตัวสร้างเป็นคุณสมบัติตัวพิมพ์
ngOnInit ()ถูกเรียกหลังจากตัวสร้างและ ngOnInit ถูกเรียกหลังจาก ngOnChanges แรก
เช่น:
ตัวสร้าง () -->ngOnChanges () -->ngOnInit ()
ตามที่กล่าวไว้ข้างต้นngOnChanges()
จะถูกเรียกเมื่อการเปลี่ยนแปลงค่าการเชื่อมโยงอินพุตหรือเอาต์พุต
ทั้งสองวิธีมีเป้าหมาย / ความรับผิดชอบแตกต่างกัน งานของตัวสร้าง (ซึ่งเป็นคุณสมบัติที่รองรับภาษา) คือการทำให้แน่ใจว่าการเป็นตัวแทนคงที่ ระบุเป็นอย่างอื่นเพื่อให้แน่ใจว่าอินสแตนซ์นั้นถูกต้องโดยให้ค่าที่ถูกต้องแก่สมาชิก ขึ้นอยู่กับผู้พัฒนาที่จะตัดสินใจว่า 'ถูกต้อง' หมายถึงอะไร
งานของวิธี onInit () (ซึ่งเป็นแนวคิดเชิงมุม) คือการอนุญาตให้มีการเรียกใช้เมธอดบนวัตถุที่ถูกต้อง (การแสดงค่าคงที่) แต่ละวิธีควรตรวจสอบให้แน่ใจว่าค่าคงที่ของการแทนค่าคงอยู่เมื่อเมธอดสิ้นสุดลง
นวกรรมิกควรจะใช้ในการสร้างวัตถุ 'ถูกต้อง' วิธีการ onInit ให้โอกาสในการเรียกวิธีการโทรในอินสแตนซ์ที่กำหนดไว้อย่างดี
คอนสตรัค: วิธีการสร้างในคลาส ES6 (หรือ TypeScript ในกรณีนี้) เป็นคุณลักษณะของคลาสเองมากกว่าคุณสมบัติเชิงมุม มันอยู่นอกเหนือการควบคุมของ Angular เมื่อมีการเรียกใช้ตัวสร้างซึ่งหมายความว่าไม่ใช่ตะขอที่เหมาะสมที่จะแจ้งให้คุณทราบเมื่อ Angular ได้เริ่มต้นส่วนประกอบเสร็จสิ้น เอ็นจิ้น JavaScript เรียกใช้ตัวสร้างไม่ใช่แองกูลาร์โดยตรง นี่คือเหตุผลว่าทำไมวงจรชีวิตของ ngOnInit (และ $ onInit in AngularJS) ถูกสร้างขึ้น คำนึงถึงเรื่องนี้ว่ามีสถานการณ์ที่เหมาะสมสำหรับการใช้ตัวสร้าง นี่คือเมื่อเราต้องการที่จะใช้การฉีดพึ่งพา - เป็นหลักสำหรับการพึ่งพา "เดินสาย" ในองค์ประกอบ
ในฐานะที่เป็นตัวสร้างถูกเริ่มต้นโดยเครื่องยนต์ JavaScript และ TypeScript ช่วยให้เราสามารถบอก Angular ว่าการพึ่งพาที่เราต้องการที่จะแมปกับคุณสมบัติที่เฉพาะเจาะจง
ngOnInitนั้นล้วนอยู่ที่นั่นเพื่อส่งสัญญาณให้เราทราบว่า Angular ได้ทำการเริ่มต้นส่วนประกอบเรียบร้อยแล้ว
ขั้นตอนนี้รวมถึงการส่งครั้งแรกที่การตรวจจับการเปลี่ยนแปลงกับคุณสมบัติที่เราอาจผูกกับองค์ประกอบของตัวเอง - เช่นการใช้มัณฑนากร @Input ()
ด้วยเหตุนี้คุณสมบัติ @Input () จึงมีอยู่ใน ngOnInit แต่ไม่ได้กำหนดไว้ภายในตัวสร้างโดยการออกแบบ
ตัวสร้างเป็นตัวแรกและบางครั้งมันก็เกิดขึ้นเมื่อข้อมูล @input เป็นโมฆะ! ดังนั้นเราจึงใช้ Constructor เพื่อประกาศบริการและ ngOnInit จะเกิดขึ้นหลังจากนั้น ตัวอย่างสำหรับ contrutor:
constructor(translate: TranslateService, private oauthService: OAuthService) {
translate.setDefaultLang('En');
translate.use('En');}
ตัวอย่างสำหรับ onInit:
ngOnInit() {
this.items = [
{ label: 'A', icon: 'fa fa-home', routerLink: ['/'] },
{ label: 'B', icon: 'fa fa-home', routerLink: ['/'] }]
}
ฉันคิดว่า onInit นั้นเหมือนกับ InitialComponents () ใน winForm
ในวงจรชีวิตเชิงมุม
1) หัวฉีดเชิงมุมตรวจจับพารามิเตอร์คอนสตรัคเตอร์ (s) และคลาสอินสแตนซ์
2) วงจรชีวิตการเรียกเชิงมุมถัดไป
ngOnChanges -> การโทรในพารามิเตอร์ directive binding
ngOnInit -> เริ่มการเรนเดอร์เชิงมุม ...
เรียกวิธีอื่นด้วยสถานะของวงจรชีวิตเชิงมุม
constructor
ถูกเรียกเมื่อเชิงมุม "instanciates / สร้าง" ส่วนประกอบ ngOnInit
วิธีคือเบ็ดซึ่งหมายถึงการเป็นส่วนหนึ่งของการเริ่มต้นของวงจรชีวิตส่วนประกอบ แนวปฏิบัติที่ดีคือใช้สำหรับการฉีดบริการเท่านั้น:
constructor(private
service1: Service1,
service2: Service2
){};
แม้ว่าจะเป็นไปได้ แต่คุณไม่ควรทำ "งาน" ข้างใน หากคุณต้องการเปิดใช้การกระทำบางอย่างที่ต้องเกิดขึ้นที่องค์ประกอบ "การเริ่มต้น" ให้ใช้ngOnInit
:
ngOnInit(){
service1.someWork();
};
นอกจากนี้การกระทำที่เกี่ยวข้องกับคุณสมบัติการป้อนข้อมูลที่มาจากองค์ประกอบหลักไม่สามารถทำได้ในตัวสร้าง พวกเขาควรจะอยู่ในngOnInit
วิธีการหรือเบ็ดอื่น มันเป็นสิ่งเดียวกันสำหรับองค์ประกอบที่เกี่ยวข้องกับมุมมอง (DOM) ตัวอย่างเช่นองค์ประกอบมุมมองเด็ก :
@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
};
constructor()
จะใช้ในการทำฉีดพึ่งพา
ngOnInit()
, ngOnChanges()
และngOnDestroy()
อื่น ๆ เป็นวิธีวงจร ngOnChanges()
จะเป็นคนแรกที่ถูกเรียกก่อนหน้าngOnInit()
นี้เมื่อค่าของการเปลี่ยนแปลงคุณสมบัติที่ถูกผูกไว้มันจะไม่ถูกเรียกถ้าไม่มีการเปลี่ยนแปลง ngOnDestroy()
ถูกเรียกเมื่อองค์ประกอบถูกลบออก หากต้องการใช้จะOnDestroy
ต้องมีการimplement
แก้ไขโดยชั้น
ฉันพบคำตอบและพยายามแปลเป็นภาษาอังกฤษ: คำถามนี้ยังคงเกิดขึ้นแม้ในการสัมภาษณ์ทางเทคนิค ในความเป็นจริงมีความคล้ายคลึงกันอย่างมากระหว่างทั้งสอง แต่ยังมีความแตกต่างบางอย่าง
ตัวสร้างเป็นส่วนหนึ่งของ ECMAScript ในทางกลับกัน ngOnInit () เป็นแนวคิดเกี่ยวกับมุม
เราสามารถเรียกใช้ตัวสร้างในคลาสทั้งหมดแม้ว่าเราจะไม่ใช้ Angular
LifeCycle: นวกรรมิกถูกเรียกมาก่อน ngOnInt ()
ในตัวสร้างเราไม่สามารถเรียกองค์ประกอบ HTML อย่างไรก็ตามใน ngOnInit () เราทำได้
โดยทั่วไปแล้วการเรียกใช้บริการใน ngOnInit () และไม่ได้อยู่ในตัวสร้าง
นวกรรมิก
ฟังก์ชั่นคอนสตรัคเตอร์มาพร้อมกับคลาสทุกคลาสคอนสตรัคเตอร์ไม่เฉพาะกับแองกูลาร์ แต่เป็นแนวคิดที่ได้มาจากการออกแบบเชิงวัตถุ ตัวสร้างสร้างอินสแตนซ์ของคลาสองค์ประกอบ
OnInit
ngOnInit
ฟังก์ชั่นเป็นหนึ่งในวิธีวงจรชีวิตเป็นองค์ประกอบเชิงมุมของ วิธีวงจรชีวิต (หรือ hooks) ในองค์ประกอบเชิงมุมช่วยให้คุณสามารถเรียกใช้ชิ้นส่วนของรหัสในขั้นตอนต่าง ๆ ของชีวิตของส่วนประกอบ ซึ่งแตกต่างจากวิธีการสร้างวิธีngOnInit
การมาจากอินเทอร์เฟซแบบ Angular ( OnInit
) ที่คอมโพเนนต์ต้องการนำมาใช้เพื่อใช้วิธีนี้ ngOnInit
วิธีการที่เรียกว่าไม่นานหลังจากที่องค์ประกอบที่จะถูกสร้างขึ้น
ตัวสร้างจะถูกดำเนินการเมื่อชั้นมีการยกตัวอย่าง มันไม่มีอะไรเกี่ยวข้องกับมุม มันเป็นคุณสมบัติของ Javascript และ Angular ไม่สามารถควบคุมมันได้
ngOnInit เป็นแบบ Angular ที่เจาะจงและถูกเรียกเมื่อ Angular ได้เริ่มต้นองค์ประกอบด้วยคุณสมบัติอินพุตทั้งหมด
คุณสมบัติ @Input มีอยู่ภายใต้ตะขอวงจรชีวิต ngOnInit สิ่งนี้จะช่วยให้คุณทำการเริ่มต้นบางอย่างเช่นรับข้อมูลจากเซิร์ฟเวอร์ส่วนหลัง ฯลฯ เพื่อแสดงในมุมมอง
@ คุณสมบัติการป้อนข้อมูลจะแสดงขึ้นเป็นไม่ได้กำหนดไว้ภายในตัวสร้าง
ตัวสร้างเป็นฟังก์ชั่นที่ดำเนินการเมื่อมีการสร้างส่วนประกอบ (หรือคลาสอื่น)
ngOnInitเป็นฟังก์ชั่นที่อยู่ในกลุ่มวิธีวงจรชีวิตขององค์ประกอบและพวกเขาจะถูกดำเนินการในช่วงเวลาที่แตกต่างกันขององค์ประกอบของเรา (นั่นคือเหตุผลที่ชื่อวงจรชีวิต) นี่คือรายการของพวกเขาทั้งหมด: