Angular默认提供了生命周期钩子ngOnInit。
为什么要使用ngOnInit,如果我们已经有一个构造函数?
Angular默认提供了生命周期钩子ngOnInit。
为什么要使用ngOnInit,如果我们已经有一个构造函数?
当前回答
Constructor()用于进行依赖注入。
ngOnInit(), ngOnChanges()和ngOnDestroy()等都是生命周期方法。ngOnChanges()将是第一个被调用的,在ngOnInit()之前,当绑定属性的值发生变化时,如果没有变化,它将不会被调用。ngOnDestroy()在移除组件时被调用。要使用它,OnDestroy需要由类实现。
其他回答
我认为最好的例子是使用服务。假设我想在我的组件“激活”时从我的服务器获取数据。假设我还想在从服务器获取数据后对数据做一些额外的处理,也许我得到了一个错误,想要以不同的方式记录它。
在构造函数上使用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();
};
}
它使它更容易看到,所以当我初始化时,我只是在组件中调用我的函数而不是在其他地方寻找它。实际上,它只是另一个工具,可以让你在将来更容易阅读和使用。此外,我发现将函数调用放在构造函数中是非常糟糕的实践!
首先,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!');
}
}
Constructor()用于进行依赖注入。
ngOnInit(), ngOnChanges()和ngOnDestroy()等都是生命周期方法。ngOnChanges()将是第一个被调用的,在ngOnInit()之前,当绑定属性的值发生变化时,如果没有变化,它将不会被调用。ngOnDestroy()在移除组件时被调用。要使用它,OnDestroy需要由类实现。
《Angular中构造函数和ngOnInit的本质区别》一文从多个角度探讨了其中的区别。这个答案提供了与组件初始化过程相关的最重要的差异解释,也显示了使用上的差异。
Angular的引导过程包括两个主要阶段:
构造组件树 运行变更检测
当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的绑定,并在MyAppComponent类上调用ngOnInit。然后它继续更新child-comp的绑定,并在ChildComponent类上调用ngOnInit。
你可以在构造函数或ngOnInit中进行初始化逻辑,这取决于你需要什么。例如,本文介绍了如何在@ViewChild查询被求值之前获取ViewContainerRef,这篇文章展示了可以要求在构造函数中执行什么类型的初始化逻辑。
这里有一些文章可以帮助你更好地理解这个话题:
关于Angular中的变更检测,你需要知道的一切 Angular的$digest在Angular的新版本中重生了 属性绑定的机制会在Angular中更新
该构造函数在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
};