Difference between Constructor and ngOnInit

2018-12-31 04:07发布

Angular provides life cycle hook ngOnInit by default.

Why should ngOnInit be used, if we already have a constructor?

20条回答
裙下三千臣
2楼-- · 2018-12-31 04:20

In the Angular life-cycles

1) Angular injector detect constructor parameter('s) and instantiate class.

2) Next angular call life-cycle

Angular Lifecycle Hooks

ngOnChanges --> Call in directive parameters binding.

ngOnInit --> Start angular rendering...

Call other method with state of angular life-cycle.

查看更多
爱死公子算了
3楼-- · 2018-12-31 04:23

The main difference between constructor and ngOnInit is that ngOnInit is lifecycle hook and runs after constructor. Component interpolated template and input initial values aren't available in constructor, but they are available in ngOnInit.

The practical difference is how ngOnInit affects how the code is structured. Most initialization code can be moved to ngOnInit - as long as this doesn't create race conditions.

Constructor antipattern

A substantial amount of initialization code makes constructor method hard to extend, read and test.

A usual recipe for separating initialization logic from class constructor is to move it to another method like init:

class Some {
  constructor() {
    this.init();
  }

  init() {...}
}

ngOnInit can serve this purpose in components and directives:

constructor(
  public foo: Foo,
  /* verbose list of dependencies */
) {
  // time-sensitive initialization code
  this.bar = foo.getBar();
}

ngOnInit() {
  // rest of initialization code
}

Dependency injection

The primary role of class constructors in Angular is dependency injection. Constructors are also used for DI annotation in TypeScript. Almost all dependencies are assigned as properties to class instance.

Average component/directive constructor is already big enough because it can have multiline signature due to dependencies, putting unnecessary intialization logic to constructor body contributes to the antipattern.

Asynchronous initialization

Asynchronous initialization constructor can often be considered antipattern and have smell because class instantiation finishes before asynchronous routine does, and this can create race conditions. If it's not the case, ngOnInit and other lifecycle hooks are better places for this, particularly because they can benefit from async syntax:

constructor(
  public foo: Foo,
  public errorHandler: ErrorHandler
) {}

async ngOnInit() {
  try {
    await this.foo.getBar();
    await this.foo.getBazThatDependsOnBar();
  } catch (err) {
    this.errorHandler.handleError(err);
  }
}

If there are race conditions (including the one that a component shouldn't appear on initialization error), asynchronous initialization routine should take place before component instantiation and be moved to parent component, router guard, etc.

Unit testing

ngOnInit is more flexible than a constructor and provides some benefits for unit testing that are explained in detail in this answer.

Considering that ngOnInit isn't called automatically on component compilation in unit tests, methods that are called in ngOnInit can be spied or mocked after component instantiation.

In exceptional cases ngOnInit can be entirely stubbed to provide isolation for other component units (for instance, some template logic).

Inheritance

Child classes can only augment constructors, not replace them.

Since this cannot be referred before super(), this puts restrictions on initialization precedence.

Considering that Angular component or directive uses ngOnInit for time-insensitive initialization logic, child classes can chose whether super.ngOnInit() is called and when:

ngOnInit() {
  this.someMethod();
  super.ngOnInit();
}

This would be impossible to implement with constructor alone.

查看更多
谁念西风独自凉
4楼-- · 2018-12-31 04:24

The first one (constructor) is related to the class instantiation and has nothing to do with Angular2. I mean a constructor can be used on any class. You can put in it some initialization processing for the newly created instance.

The second one corresponds to a lifecycle hook of Angular2 components:

Quoted from official angular's website:

  • ngOnChanges is called when an input or output binding value changes
  • ngOnInit is called after the first ngOnChanges

So you should use ngOnInit if initialization processing relies on bindings of the component (for example component parameters defined with @Input), otherwise the constructor would be enough...

查看更多
残风、尘缘若梦
5楼-- · 2018-12-31 04:26

Constructor: The constructor method on an ES6 class (or TypeScript in this case) is a feature of a class itself, rather than an Angular feature. It’s out of Angular’s control when the constructor is invoked, which means that it’s not a suitable hook to let you know when Angular has finished initialising the component. JavaScript engine calls the constructor, not Angular directly. Which is why the ngOnInit (and $onInit in AngularJS) lifecycle hook was created. Bearing this in mind, there is a suitable scenario for using the constructor. This is when we want to utilise dependency injection - essentially for “wiring up” dependencies into the component.

As the constructor is initialised by the JavaScript engine, and TypeScript allows us to tell Angular what dependencies we require to be mapped against a specific property.

ngOnInit is purely there to give us a signal that Angular has finished initialising the component.

This phase includes the first pass at Change Detection against the properties that we may bind to the component itself - such as using an @Input() decorator.

Due to this, the @Input() properties are available inside ngOnInit, however are undefined inside the constructor, by design

查看更多
伤终究还是伤i
6楼-- · 2018-12-31 04:27

The above answers don't really answer this aspect of the original question: What is a lifecycle hook? It took me a while to understand what that means until I thought of it this way.

1) Say your component is a human. Humans have lives that include many stages of living, and then we expire.

2) Our human component could have the following lifecycle script: Born, Baby, Grade School, Young Adult, Mid-age Adult, Senior Adult, Dead, Disposed of.

3) Say you want to have a function to create children. To keep this from getting complicated, and rather humorous, you want your function to only be called during the Young Adult stage of the human component life. So you develop a component that is only active when the parent component is in the Young Adult stage. Hooks help you do that by signaling that stage of life and letting your component act on it.

Fun stuff. If you let your imagination go to actually coding something like this it gets complicated, and funny.

查看更多
高级女魔头
7楼-- · 2018-12-31 04:29

Angular 2 Constructors:-

  1. The constructor is a default method runs when component is being constructed.
  2. The constructor is a typescript feature and it is used only for a class instantiations and nothing to do with Angular 2.
  3. The constructor called first time before the ngOnInit().

Angular 2 ngOnInit:-

  1. The ngOnInit event is an Angular 2 life-cycle event method that is called after the first ngOnChanges and the ngOnInit method is use to parameters defined with @Input otherwise the constructor is OK.

  2. The ngOnInit is called after the constructor and ngOnInit is called after the first ngOnChanges.

  3. The ngOnChanges is called when an input or output binding value changes.

Following diagram explains the lie cycle of Angular. From that you can get an idea about the order in which each one is called.

enter image description here

查看更多
登录 后发表回答