Angular默认提供了生命周期钩子ngOnInit。
为什么要使用ngOnInit,如果我们已经有一个构造函数?
Angular默认提供了生命周期钩子ngOnInit。
为什么要使用ngOnInit,如果我们已经有一个构造函数?
当前回答
该构造函数在Angular“实例化/构造”组件时被调用。 ngOnInit方法是一个钩子,它表示组件生命周期的初始化部分。 一个好的做法是只在服务注入时使用它:
constructor(private
service1: Service1,
service2: Service2
){};
即使有可能,你也不应该在里面做一些“工作”。 如果你想在组件“初始化”时启动一些动作,请使用ngOnInit:
ngOnInit(){
service1.someWork();
};
此外,涉及来自父组件的输入属性的操作不能在构造函数中完成。 它们应该放在ngOnInit方法或其他钩子中。 与视图(DOM)相关的元素也是一样的,例如viewchild元素:
@Input itemFromParent: string;
@ViewChild('childView') childView;
constructor(){
console.log(itemFromParent); // KO
// childView is undefined here
};
ngOnInit(){
console.log(itemFromParent); // OK
// childView is undefined here, you can manipulate here
};
其他回答
构造函数: ES6类(这里是TypeScript)的构造函数方法是类本身的特性,而不是Angular的特性。当调用构造函数时,它不在Angular的控制范围内,这意味着它不是一个合适的钩子来告诉你Angular何时完成了组件的初始化。JavaScript引擎调用构造函数,而不是直接调用Angular。这就是为什么创建了ngOnInit(和AngularJS中的$onInit)生命周期钩子。记住这一点,有一个使用构造函数的合适场景。这就是我们想要利用依赖注入的时候——本质上是为了将依赖“连接”到组件中。
由于构造函数是由JavaScript引擎初始化的,TypeScript允许我们告诉Angular,我们需要将哪些依赖关系映射到特定的属性上。
ngOnInit只是给我们一个信号,表明Angular已经完成了组件的初始化。
这个阶段包括针对我们可能绑定到组件本身的属性的Change Detection的第一步——比如使用@Input()装饰器。
因此,@Input()属性在ngOnInit中是可用的,但是在构造函数中是未定义的
这里需要注意两点:
每当该类创建对象时,都会调用构造函数。 一旦组件创建,就调用ngOnInit。
两者都有不同的可用性。
首先,ngOnInit是Angular生命周期的一部分,而constructor是ES6 JavaScript类的一部分,所以主要的区别就是从这里开始的!
请看下面我创建的图表,它展示了Angular的生命周期。
在Angular2+中,我们使用构造函数为我们做DI(依赖注入),而在Angular 1中,它是通过调用String方法并检查注入了哪个依赖。
正如你在上面的图表中看到的,ngOnInit是在构造函数准备好之后发生的,ngOnChnages和在组件为我们准备好之后被触发。所有的初始化都可以在这个阶段进行,一个简单的示例是注入一个服务并在init上初始化它。
好的,我还分享了一个示例代码给你看,看看我们如何在下面的代码中使用ngOnInit和构造函数:
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!');
}
}
该构造函数在Angular“实例化/构造”组件时被调用。 ngOnInit方法是一个钩子,它表示组件生命周期的初始化部分。 一个好的做法是只在服务注入时使用它:
constructor(private
service1: Service1,
service2: Service2
){};
即使有可能,你也不应该在里面做一些“工作”。 如果你想在组件“初始化”时启动一些动作,请使用ngOnInit:
ngOnInit(){
service1.someWork();
};
此外,涉及来自父组件的输入属性的操作不能在构造函数中完成。 它们应该放在ngOnInit方法或其他钩子中。 与视图(DOM)相关的元素也是一样的,例如viewchild元素:
@Input itemFromParent: string;
@ViewChild('childView') childView;
constructor(){
console.log(itemFromParent); // KO
// childView is undefined here
};
ngOnInit(){
console.log(itemFromParent); // OK
// childView is undefined here, you can manipulate here
};
我将添加一个重要的东西,在上面的解释中被跳过,并解释什么时候你必须使用ngOnInit。
如果你通过ViewChildren, ContentChildren或ElementRef对组件的DOM进行任何操作,你的原生元素在构造函数阶段将不可用。
然而,由于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
}
}