Angular Performance Optimisation: Change Detection and OnPush

Angular Performance Optimisation: Change Detection and OnPush

Angular Performance Optimisation: Change Detection and OnPush

Angular's default change detection checks every component on every event. Learning to control this gives you significant performance gains in large applications.

Step 1 — OnPush Change Detection

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

@Component({
  selector:         'app-product-card',
  standalone:       true,
  changeDetection:  ChangeDetectionStrategy.OnPush,
  template: `...`,
})
export class ProductCardComponent {
  @Input() product!: Product;
  // Angular only checks this component when:
  // 1. An @Input reference changes
  // 2. An event fires inside the component
  // 3. An async pipe emits a new value
  // 4. ChangeDetectorRef.markForCheck() is called
}

Step 2 — trackBy in @for Loops

<!-- New syntax — track expression -->
@for (item of items; track item.id) {
  <app-item [item]="item" />
}

<!-- Old *ngFor with trackBy function -->
<li *ngFor="let item of items; trackBy: trackById">
trackById(index: number, item: Item): number {
  return item.id; // Angular reuses DOM nodes when id is unchanged
}

Step 3 — Pure Pipes for Expensive Transforms

@Pipe({ name: 'filterItems', standalone: true, pure: true }) // pure: true (default)
export class FilterItemsPipe implements PipeTransform {
  transform(items: Item[], search: string): Item[] {
    // Only re-runs when items reference or search value changes
    return items.filter(i => i.name.includes(search));
  }
}

Step 4 — Zoneless with Signals

// app.config.ts — opt in to experimental zoneless
import { provideExperimentalZonelessChangeDetection } from '@angular/core';

export const appConfig: ApplicationConfig = {
  providers: [
    provideExperimentalZonelessChangeDetection(),
  ],
};
// Now Angular only re-renders components when a signal they read changes
All Comments