angular
Yesterday

В чём разница между constructor() и ngOnInit()?

На первый взгляд, оба метода вызываются при создании компонента, но их назначение и место в жизненном цикле приложения существенно различаются.

Конструктор – это стандартная часть языка TypeScript/JavaScript, а ngOnInit – это специальный метод, который Angular вызывает как часть своего lifecycle (жизненного цикла).

При создании экземпляра класса (компонента) Angular вызывает его конструктор и передаёт в него все необходимые DI зависимости (сервисы, указанные в параметрах конструктора). То есть уже на этапе конструктора вы можете обратиться к своим сервисам и вызвать у них нужные методы. Однако @Input()ы компонента могут ещё не быть инициализированы. Именно поэтому при прохождении код-ревью часть обращают внимание именно на логику внутри конструктора.

Метод ngOnInit запускается после инициализации всех входных свойств. Это значит, что компоненту будут доступны все данные из родительских компонентов, и Angular уже совершил все необходимые привязки данных Поэтому основную бизнес-логику инициализации (например, подгрузку данных, настройку подписок на сервисы и работу со значениями @Input()) чаще всего размещают именно внутри ngOnInit.

Рассмотрим на примере:

import { Component, OnInit, Input } from '@angular/core';
import { MyService } from './my.service';

@Component({
  selector: 'app-my-component',
  template: `
    <h1>Hello, {{ userName }}!</h1>
  `
})
export class MyComponent implements OnInit {
  @Input() userName!: string;

  constructor(private myService: MyService) {
    // Здесь DI уже сработал, и myService доступен.
    // Но значению @Input() userName ещё может не быть присвоено фактическое значение.
    console.log('constructor:', this.userName); // Скорее всего здесь будет undefined
  }

  ngOnInit(): void {
    // На момент вызова ngOnInit все входные свойства уже инициализированы.
    console.log('ngOnInit:', this.userName); // Здесь уже будет фактическое значение
    // Здесь обычно размещают код инициализации, например подписки на сервисы или подготовку данных
    this.myService.loadData(this.userName).subscribe(data => {
      // ...
    });
  }
}