Angular默认提供了生命周期钩子ngOnInit。

为什么要使用ngOnInit,如果我们已经有一个构造函数?


当前回答

在Angular生命周期中

1) Angular注入器检测构造函数参数和实例化类。

2)下一个角调用生命周期

Angular生命周期钩子

调用指令参数绑定。

开始角渲染…

调用具有角生命周期状态的其他方法。

其他回答

构造函数是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我们想在特定组件中使用什么类型的依赖。

《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
};

构造函数是第一个执行的,当@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()。

Constructor()用于进行依赖注入。

ngOnInit(), ngOnChanges()和ngOnDestroy()等都是生命周期方法。ngOnChanges()将是第一个被调用的,在ngOnInit()之前,当绑定属性的值发生变化时,如果没有变化,它将不会被调用。ngOnDestroy()在移除组件时被调用。要使用它,OnDestroy需要由类实现。