Angular默认提供了生命周期钩子ngOnInit。
为什么要使用ngOnInit,如果我们已经有一个构造函数?
Angular默认提供了生命周期钩子ngOnInit。
为什么要使用ngOnInit,如果我们已经有一个构造函数?
当前回答
《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,或者更好的依赖注入器(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在注释中提出的建议)
首先,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的本质区别》一文从多个角度探讨了其中的区别。这个答案提供了与组件初始化过程相关的最重要的差异解释,也显示了使用上的差异。
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中更新
构造函数在类实例化时执行。它与棱角无关。这是Javascript的特性,Angular无法控制它
ngOnInit是Angular特有的,当Angular用所有输入属性初始化组件时,它会被调用
@Input属性在ngOnInit生命周期钩子下可用。这将帮助你做一些初始化的事情,比如从后端服务器获取数据等显示在视图中
@Input属性在构造函数中显示为未定义
简短而简单的回答是,
构造函数:构造函数是在构造组件时(默认情况下)运行的默认方法。当创建类的实例时,也会调用构造函数(默认方法)。换句话说,当构建组件或/和创建实例时,调用构造函数(默认方法)并调用其中编写的相关代码。基本上,在Angular2中,当组件被构造以供进一步使用时,它被用来注入服务之类的东西。
OnInit: ngOnInit是组件的生命周期钩子,当组件初始化时,它首先在构造函数(默认方法)之后运行。
因此,你的构造函数将首先被调用,Oninit将在构造函数方法之后被调用。
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()
}
}
资源:生命周期钩子
你可以查看这个小演示,它展示了这两件事的实现。