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
};
其他回答
两种方法都有不同的目标/职责。构造函数(这是语言支持的特性)的任务是确保表示不变量成立。否则,通过给成员正确的值来确保实例是有效的。“正确”的含义由开发者决定。
onInit()方法(这是一个angular概念)的任务是允许在正确的对象上调用方法(表示不变)。每个方法都应该依次确保在方法终止时表示不变量保持不变。
构造函数应该用来创建“正确的”对象,onInit方法让你有机会在一个定义良好的实例中调用方法调用。
构造函数是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我们想在特定组件中使用什么类型的依赖。
我找到了答案,试着把它翻译成英语: 即使在技术面试中,这个问题仍然会出现。事实上,两者之间有很大的相似之处,但也有一些不同。
构造函数是ECMAScript的一部分。另一方面,ngOnInit()是angular的概念。 即使不使用Angular,我们也可以在所有类中调用构造函数 生命周期:构造函数在ngOnInt()之前调用 在构造函数中,我们不能调用HTML元素。然而,在ngOnInit()中我们可以。 通常,服务调用在ngOnInit()中,而不是在构造函数中 来源:http://www.angular-tuto.com/Angular/Component Diff
《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中更新
构造函数: ES6类(这里是TypeScript)的构造函数方法是类本身的特性,而不是Angular的特性。当调用构造函数时,它不在Angular的控制范围内,这意味着它不是一个合适的钩子来告诉你Angular何时完成了组件的初始化。JavaScript引擎调用构造函数,而不是直接调用Angular。这就是为什么创建了ngOnInit(和AngularJS中的$onInit)生命周期钩子。记住这一点,有一个使用构造函数的合适场景。这就是我们想要利用依赖注入的时候——本质上是为了将依赖“连接”到组件中。
由于构造函数是由JavaScript引擎初始化的,TypeScript允许我们告诉Angular,我们需要将哪些依赖关系映射到特定的属性上。
ngOnInit只是给我们一个信号,表明Angular已经完成了组件的初始化。
这个阶段包括针对我们可能绑定到组件本身的属性的Change Detection的第一步——比如使用@Input()装饰器。
因此,@Input()属性在ngOnInit中是可用的,但是在构造函数中是未定义的