Angular Change Detection: When and Why OnPush Makes a Difference


Published: November 15, 2021


Introduction

Change detection in Angular is a fundamental concept that impacts how your application updates the UI in response to data changes. Understanding how Angular’s Change Detection Strategy works is crucial for building high-performance applications.

In this post, we’ll explore:

  • The basics of Angular’s default change detection mechanism
  • How ChangeDetectionStrategy.OnPush changes the game
  • When to use OnPush and why it improves rendering performance
  • Practical examples illustrating both strategies

Angular’s Default Change Detection

By default, Angular uses the Default change detection strategy. This means:

  • Every time Angular runs change detection (e.g., user input, HTTP responses, timers), it checks every component in the component tree for data changes.
  • Angular walks the entire tree and updates any bindings that have changed.

Why is this inefficient sometimes?

In complex or large applications, checking every component frequently—even those whose inputs haven’t changed—can hurt performance.


Enter OnPush: Smarter Change Detection

ChangeDetectionStrategy.OnPush tells Angular:

Only check this component (and its subtree) when:

  • Its @Input() properties change (by reference)
  • An event originated from the component or one of its children
  • You manually trigger change detection

This means Angular skips checking the component unless it has a clear reason to believe something changed. This reduces unnecessary checks and improves app responsiveness.


How to Use OnPush

Add the changeDetection property to your component decorator:

import { Component, ChangeDetectionStrategy, Input } from '@angular/core';

@Component({
  selector: 'app-user-profile',
  template: `
    <p>{{ user.name }}</p>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class UserProfileComponent {
  @Input() user!: { name: string };
}

Example: Default vs OnPush

Let’s see a simple demo.

App Component (Parent):

@Component({
  selector: 'app-root',
  template: `
    <button (click)="updateName()">Update Name</button>
    <app-user-profile [user]="user"></app-user-profile>
  `
})
export class AppComponent {
  user = { name: 'Alice' };

  updateName() {
    // Mutating the property without changing reference
    this.user.name = 'Bob';
  }
}

UserProfileComponent with Default change detection:

  • The template will update even when the user object reference remains the same because Angular checks everything every cycle.

UserProfileComponent with OnPush:

  • The template will NOT update because the user input reference didn’t change (only a property inside it changed).

Fixing OnPush Update Issues

To work correctly with OnPush, immutable data or new object references must be passed.

Modify the updateName method:

updateName() {
  // Create a new object reference
  this.user = { ...this.user, name: 'Bob' };
}

Now, OnPush detects the change and updates the UI.


When to Use OnPush

  • Your components have immutable inputs or you can guarantee new references when data changes.
  • You want to reduce the number of checks Angular performs.
  • You’re building a complex UI with many components where performance matters.
  • Your app uses push-based state management (e.g., NgRx, RxJS).

Detecting and Manually Triggering Change Detection

Sometimes, you might have to manually trigger change detection (e.g., after an asynchronous event outside Angular’s zone):

import { ChangeDetectorRef } from '@angular/core';

constructor(private cd: ChangeDetectorRef) {}

someAsyncMethod() {
  // After async event
  this.cd.markForCheck(); // Marks the component to be checked next cycle
  // Or
  this.cd.detectChanges(); // Immediately runs change detection for this component
}

Summary

StrategyWhen It ChecksPerformanceUse Case
DefaultEvery change detection cycleLess performantSmall apps, simple UIs
OnPushOnly when inputs change or events fireMore performantComplex apps, immutable data

Switching to OnPush is one of the most effective ways to optimize Angular apps, but it requires disciplined state management.


Further Reading


Ready to boost your Angular app’s performance? Try switching key components to OnPush today!

Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply

Your email address will not be published. Required fields are marked *