Angular默认提供了生命周期钩子ngOnInit。
为什么要使用ngOnInit,如果我们已经有一个构造函数?
Angular默认提供了生命周期钩子ngOnInit。
为什么要使用ngOnInit,如果我们已经有一个构造函数?
当前回答
构造函数: ES6类(这里是TypeScript)的构造函数方法是类本身的特性,而不是Angular的特性。当调用构造函数时,它不在Angular的控制范围内,这意味着它不是一个合适的钩子来告诉你Angular何时完成了组件的初始化。JavaScript引擎调用构造函数,而不是直接调用Angular。这就是为什么创建了ngOnInit(和AngularJS中的$onInit)生命周期钩子。记住这一点,有一个使用构造函数的合适场景。这就是我们想要利用依赖注入的时候——本质上是为了将依赖“连接”到组件中。
由于构造函数是由JavaScript引擎初始化的,TypeScript允许我们告诉Angular,我们需要将哪些依赖关系映射到特定的属性上。
ngOnInit只是给我们一个信号,表明Angular已经完成了组件的初始化。
这个阶段包括针对我们可能绑定到组件本身的属性的Change Detection的第一步——比如使用@Input()装饰器。
因此,@Input()属性在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!');
}
}
我认为最好的例子是使用服务。假设我想在我的组件“激活”时从我的服务器获取数据。假设我还想在从服务器获取数据后对数据做一些额外的处理,也许我得到了一个错误,想要以不同的方式记录它。
在构造函数上使用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);
};
}
对于构造函数,我可以只调用我的_userService并填充我的user_list,但也许我想对它做一些额外的事情。比如确保所有内容都是大写的,我不完全确定我的数据是如何通过的。
这让使用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();
};
}
它使它更容易看到,所以当我初始化时,我只是在组件中调用我的函数而不是在其他地方寻找它。实际上,它只是另一个工具,可以让你在将来更容易阅读和使用。此外,我发现将函数调用放在构造函数中是非常糟糕的实践!
构造函数是类的默认方法,在类实例化时执行,并确保类及其子类中的字段正确初始化。Angular,或者更好的依赖注入器(DI),会分析构造函数的参数,当它通过调用new MyClass()创建一个新实例时,它会尝试找到与构造函数参数类型匹配的提供程序,解析它们并将它们传递给构造函数
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进行所有的初始化/声明,避免在构造函数中工作。构造函数应该只用于初始化类成员,而不应该做实际的“工作”。
因此,您应该使用构造函数()来设置依赖注入,而不是其他什么。ngOnInit()是更好的“开始”的地方——它是解析组件绑定的地方。
更多信息请参考这里:
https://angular.io/api/core/OnInit Angular组件构造函数Vs OnInit
需要注意的是,@Input值在构造函数中是不可访问的(感谢@tim在注释中提出的建议)
构造函数是第一个执行的,当@input data为空时有时会发生这种情况! 所以我们使用构造函数注入服务,ngOnInit在后面发生。 构造函数示例:
constructor(translate: TranslateService, private oauthService: OAuthService) {
translate.setDefaultLang('En');
translate.use('En');}
示例ngOnInit:
ngOnInit() {
this.items = [
{ label: 'A', icon: 'fa fa-home', routerLink: ['/'] },
{ label: 'B', icon: 'fa fa-home', routerLink: ['/'] }]
}
我认为ngOnInit就像winForm中的InitialComponents()。
构造函数是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)实现的,而不是Angular)。
new CONSTRUCTORTEST();
这就是为什么Angular中有ngOnInit生命周期钩子。ngOnInit在Angular完成组件初始化后才会呈现。
import {Component} from '@angular/core';
@Component({})
class NGONINITTEST implements onInit{
constructor(){}
//ngOnInit calls by Angular
ngOnInit(){
console.log("Testing ngOnInit");
}
}
首先,我们实例化如下所示的类,它发生在构造函数方法的立即运行中。
let instance = new NGONINITTEST();
Angular会在必要时调用ngOnInit,如下所示:
instance.ngOnInit();
但是你可能会问为什么我们在Angular中使用构造函数?
答案是依赖注入。正如前面提到的,当类被实例化时(在Angular调用ngOnInit之前),JavaScript引擎会立即调用构造函数,因此typescript帮助我们获得在构造函数中定义的依赖类型,并最终告诉Angular我们想在特定组件中使用什么类型的依赖。