Angular lifecycle hooks: when do they run, and what should you put in each?

LowIntermediateAngular
Preparing for interviews?

Use guided tracks for structured prep, then practice company-specific question sets when you want targeted interview coverage.

Quick Answer

Angular lifecycle hooks are framework callbacks on components/directives that run at specific moments (creation, input changes, content/view init + checks, destruction). Interviewers care less about memorizing names and more about choosing the correct hook for inputs, DOM/ViewChild, content projection, change-detection edge cases, and cleanup. Framework focus: Angular templates + standalone components, @Input/@Output, and RxJS/async pipe patterns.

Answer

Core idea

Hooks are Angular-called methods that let you run code at predictable lifecycle points. The practical skill is picking the right hook:
Inputs changed? ngOnChanges
Initialize once? ngOnInit
Projected content? ngAfterContent*
DOM / ViewChild? ngAfterViewInit
Cleanup? ngOnDestroy

Hook

When it runs

Frequency

What it’s for

constructor

Class instantiation (before Angular bindings)

Once

DI + minimal field setup. No inputs, no DOM.

ngOnChanges(changes)

After an @Input binding changes

Many times (or zero if no inputs)

React to input changes; validate/normalize; derive state from inputs.

ngOnInit()

After first ngOnChanges (or after first binding setup)

Once

Initialization that depends on inputs/services; start streams; fetch data.

ngDoCheck()

During every change detection run

Many times

Rare: custom change tracking when default checks aren’t enough (use carefully).

ngAfterContentInit()

After projected content (<ng-content>) is set

Once

Work that needs @ContentChild/@ContentChildren to exist.

ngAfterContentChecked()

After every check of projected content

Many times

Rare: respond to projected content changes (avoid heavy work).

ngAfterViewInit()

After component view + child views are created

Once

Safe DOM/ViewChild access; measure/focus; init 3rd-party widgets.

ngAfterViewChecked()

After every check of the component view

Many times

Rare: respond after view checks (avoid state writes here).

ngOnDestroy()

Right before Angular destroys the instance

Once

Cleanup: subscriptions, timers, listeners, 3rd-party teardown.

Lifecycle hooks, timing, and intent

Scenario

Correct hook

Why

Initialize streams / fetch data

ngOnInit

Runs once when bindings are ready.

Derive state from @Input() changes

ngOnChanges

You get SimpleChanges with prev/current values.

Access @ViewChild / DOM measurements / focus

ngAfterViewInit

View is guaranteed to exist (default static: false).

Access projected content via @ContentChild

ngAfterContentInit

Projected content is initialized (different from the view).

Tear down subscriptions, intervals, 3rd-party widgets

ngOnDestroy

Last guaranteed cleanup point.

Picking the right hook (what interviewers actually test)
TYPESCRIPT
import {
  AfterContentChecked,
  AfterContentInit,
  AfterViewChecked,
  AfterViewInit,
  Component,
  Input,
  OnChanges,
  OnDestroy,
  OnInit,
  SimpleChanges,
  ViewChild,
  ElementRef,
} from '@angular/core';

@Component({
  selector: 'app-life',
  template: `
    <p #p>Hello</p>
    <ng-content></ng-content>
  `
})
export class LifeComponent
  implements
    OnChanges,
    OnInit,
    AfterContentInit,
    AfterContentChecked,
    AfterViewInit,
    AfterViewChecked,
    OnDestroy {

  @Input() value = 0;
  @ViewChild('p') p?: ElementRef<HTMLParagraphElement>;

  constructor() {
    console.log('constructor');
  }

  ngOnChanges(changes: SimpleChanges): void {
    if (changes['value']) {
      console.log('ngOnChanges', changes['value'].previousValue, '->', changes['value'].currentValue);
    }
  }

  ngOnInit(): void {
    console.log('ngOnInit');
  }

  ngAfterContentInit(): void {
    console.log('ngAfterContentInit');
  }

  ngAfterContentChecked(): void {
    console.log('ngAfterContentChecked');
  }

  ngAfterViewInit(): void {
    console.log('ngAfterViewInit');
    // Safe: ViewChild available (default static:false)
    this.p?.nativeElement.focus?.();
  }

  ngAfterViewChecked(): void {
    console.log('ngAfterViewChecked');
  }

  ngOnDestroy(): void {
    console.log('ngOnDestroy');
  }
}
                  

Execution order (practical)

First render (typical):
constructor → ngOnChanges? → ngOnInit → ngAfterContentInit → ngAfterContentChecked → ngAfterViewInit → ngAfterViewChecked

Later change-detection cycles:
ngOnChanges? → ngDoCheck → ngAfterContentChecked → ngAfterViewChecked

Note: ngOnChanges only runs for @Input changes from the parent binding; it won’t fire just because you mutated an object in-place without changing the input reference.

Pitfall (interview-grade)

What happens

Fix

Mutating bindings in ngAfterViewInit/ngAfterViewChecked

Dev mode can throw ExpressionChangedAfterItHasBeenCheckedError

Avoid sync bound writes there; schedule (microtask) or refactor logic earlier.

Forgetting cleanup

Intervals/subscriptions keep running after navigation

Use ngOnDestroy, async pipe, or takeUntilDestroyed.

Heavy work in ngAfterViewChecked/ngDoCheck

Runs often → perf issues, jank

Keep these hooks rare and cheap; prefer pure derivations and OnPush patterns.

Expecting ngOnChanges on internal mutations

No call if input reference doesn’t change

Use immutable updates (new reference) or manual detection logic if needed.

Confusing content vs view

Using @ViewChild when you needed @ContentChild (or vice versa)

Use AfterView* for view; AfterContent* for projection.

Common lifecycle bugs seniors mention
TYPESCRIPT
import { Component, DestroyRef, inject, OnInit } from '@angular/core';
import { interval } from 'rxjs';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';

@Component({
  selector: 'app-clean',
  template: `...`
})
export class CleanComponent implements OnInit {
  private readonly destroyRef = inject(DestroyRef);

  ngOnInit(): void {
    // Auto-cleanup when the component is destroyed.
    interval(1000)
      .pipe(takeUntilDestroyed(this.destroyRef))
      .subscribe(v => console.log(v));
  }
}
                  
Summary

Lifecycle hooks are Angular callbacks around creation, binding updates, view/content init + checks, and teardown. For interviews: know ngOnChanges (inputs), ngOnInit (init once), ngAfterViewInit (DOM/ViewChild), and ngOnDestroy (cleanup), plus the content-vs-view distinction and the common pitfalls.

Similar questions
Guides
12 / 37