Understanding when Angular executes your code is vital for building bug-free applications. The lifecycle hooks provide visibility into the component's internal state.
1The Sequence of Events
A component's life starts with the constructor, followed immediately by ngOnChanges. Once inputs are settled, ngOnInit runs. After the view is composed, ngAfterViewInit fires. This sequence is deterministic. If you try to access a @ViewChild in ngOnInit, it will likely be undefined because the view hasn't been initialized yet. Mastering this order prevents the 'ExpressionChangedAfterItHasBeenCheckedError' and other common pitfalls.
2Strategic Cleanup
The ngOnDestroy hook is the most important for application health. In a single-page application, components are frequently created and destroyed as the user navigates. If you subscribe to a global stream or set a setInterval in a component, that work continues even after the component is gone unless you manually stop it in ngOnDestroy. This is the single biggest cause of memory leaks and performance degradation in large-scale Angular apps.
3Step-by-Step Breakdown
Components aren't static. They are born, they change, and they die. Angular lets you 'hook' into these moments.
The first major hook is 'ngOnInit'. It's the best place to initialize data or fetch information from a service.
If your component has @Input() properties, 'ngOnChanges' runs every time those values change. It gives you the old and new values.
Checkpoint: Which lifecycle hook is the most appropriate for performing one-time initialization, such as calling a service?
- โngOnInit
- โngOnChanges
When you need to interact with the DOM or child components, use 'ngAfterViewInit'. This runs after the template is fully rendered.
Finally, 'ngOnDestroy' is your cleanup crew. Use it to unsubscribe from Observables or clear timers before the component is removed.
Checkpoint: What is the primary purpose of the ngOnDestroy hook?
- โInitialize variables
- โPerform cleanup and prevent leaks
Lifecycle mastered! You now know exactly when and where to put your code for maximum performance and stability.
Next, we'll wrap up the Angular core by looking at Testing and Production Deployment.
Level Up ๐
Advanced cheat sheets, SEO tricks, and interview prep for this topic.
Browser Support
Fully supported.
Fully supported.
Fully supported.
Fully supported.
Accessibility (A11y)
1`ngAfterViewInit` Is the Right Place to Move Initial Focus
If a component (like a modal) needs to programmatically focus an element as soon as it renders, `ngAfterViewInit` is the correct hook โ it fires only after the view (and any `@ViewChild` references) is fully initialized, unlike `ngOnInit`, which runs before the view exists.
2`ngOnDestroy` Is Where You Clean Up Anything That Could Leave Assistive Tech in a Bad State
If a component registered a global keydown listener or an `aria-live` region reference, `ngOnDestroy` is where that must be torn down โ leaving it dangling after the component's DOM is gone can cause confusing behavior for keyboard and screen reader users navigating elsewhere in the app.
SEO Implications
- 1
Under SSR, Certain Lifecycle Hooks Behave Differently or Don't Fire the Same Way
Some browser-only lifecycle-triggered behavior (like measuring an element's rendered size in `ngAfterViewInit`) doesn't make sense or work identically during Angular Universal's server-side render pass โ code relying on browser globals within lifecycle hooks needs platform guards.
- 2
Fetching Critical Content in `ngOnInit` Ties Its SEO Visibility to SSR Timing
If `ngOnInit` triggers an HTTP request for content that should be indexable, that request must actually resolve during the server-side render (using Angular's `TransferState` or an SSR-aware data resolver) for the content to appear in the HTML a crawler receives.
Best Practices
Use `ngOnChanges` Instead of `ngOnInit` to React to Input Changes After the First Render
`ngOnInit` only runs once, right after the first `ngOnChanges` โ if a component needs to react every time an `@Input()` value changes later, `ngOnChanges` (or a getter/setter on the input) is the hook actually designed for that, not `ngOnInit`.
Always Pair Setup Logic With Matching Teardown Logic in `ngOnDestroy`
Any subscription started in `ngOnInit`, timer set with `setInterval`, or global event listener added anywhere in the component's life should have a matching cleanup in `ngOnDestroy` โ treat the two hooks as a pair, not `ngOnDestroy` as an afterthought.
Frequent Bugs
A component doesn't react when a parent updates one of its `@Input()` bindings after the initial render.
The reactive logic was placed in `ngOnInit`, which only ever runs once. Move it to `ngOnChanges`, which fires on every subsequent input change, or use an input setter that runs custom logic whenever a new value is assigned.
A `setInterval` or subscription set up in a component keeps running and causing errors long after the component has been navigated away from and destroyed.
The corresponding cleanup was never added to `ngOnDestroy` โ clear the interval with `clearInterval`, and unsubscribe from any manually-created subscriptions, in that hook to match the setup that happened earlier in the component's life.
Real-World Examples
Modal Component With Correct Focus and Cleanup Lifecycle
A modal component moves focus to itself once its view is ready (not before), and cleans up a document-level keydown listener when destroyed, preventing it from firing after the modal is gone.
ngAfterViewInit() { this.modalRef.nativeElement.focus(); }
ngOnDestroy() { document.removeEventListener('keydown', this.escHandler); }