How To Fix Slow Change Detection in Angular

Slow performance in Angular applications is often caused by inefficient change detection, especially when the app grows large or when many components re-render unnecessarily. Angular’s default change detection strategy checks every component on every event, which can slow down the UI if not handled properly.

This guide explains the causes of slow change detection and provides practical fixes used by modern Angular developers.


1. What Causes Slow Change Detection?

Angular runs change detection whenever events occur, such as:

  • Clicks, keypresses, scrolls
  • HTTP calls
  • Timers (setTimeout, intervals)
  • Observable emissions
  • Change in input bindings

When these are not optimized, Angular repeatedly checks the entire component tree, causing:

  • Slow UI updates
  • Janky scrolling
  • Delayed DOM updates
  • Freezing in large lists

2. Fix #1: Use OnPush Change Detection Strategy

The default change detection checks everything.
Switching to ChangeDetectionStrategy.OnPush tells Angular to check a component only when needed.

How to apply:

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

@Component({
  selector: 'app-user-list',
  templateUrl: './user-list.component.html',
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class UserListComponent {
  // component logic
}

Benefits:

  • Up to 40–60% faster rendering
  • Components update only when:
    • Input changes
    • Event triggered inside component
    • Observable emits new value
    • Manually marked for check

*3. Fix #2: Always Use trackBy With ngFor

Large lists cause unnecessary DOM re-renders.

<div *ngFor="let user of users; trackBy: trackById">
  {{ user.name }}
</div>
trackById(index: number, item: any) {
  return item.id;
}

Why this fixes lag?

  • Without trackBy, Angular destroys and re-creates DOM elements
  • With trackBy, Angular updates only the changed item

4. Fix #3: Move Heavy Logic Out of Templates

Avoid expensive operations directly inside templates:

Bad example:

<div>{{ calculateTotal() }}</div>

This runs on every change detection cycle.

Fix:

Run it once in TS and expose a variable:

total = this.calculateTotal();

5. Fix #4: Convert Data Streams to signals (Angular 16+)

Signals reduce unnecessary re-renders.

Example:

const counter = signal(0);
counter.update(v => v + 1);

Signals notify Angular only when actual data changes, not on every event.


6. Fix #5: Avoid Change Detection Triggers in Loops

Common mistake:

setInterval(() => {
  this.value++;
}, 10);

This triggers change detection 100 times per second.

Fix:

Run timers inside NgZone.runOutsideAngular():

this.ngZone.runOutsideAngular(() => {
  setInterval(() => {
    this.ngZone.run(() => this.value++);
  }, 1000);
});

7. Fix #6: Use Immutable Data Structures

Immutable changes help Angular detect updates faster:

this.users = [...this.users, newUser];

Instead of mutating arrays:

this.users.push(newUser); // ❌ triggers full re-check

8. Fix #7: Break Down Large Components

If one giant component handles:

  • API calls
  • Nested UI
  • Forms
  • Lists
  • Business logic

…it will cause frequent change detection cycles.

Solution:

Split it into smaller feature components with OnPush strategy.


9. Fix #8: Use Pure Pipes Instead of Methods in Templates

Angular executes template methods often.

Replace methods with pure pipes that execute only when input changes.


Final Thoughts

Most Angular performance problems are solvable with:

  • OnPush strategy
  • trackBy on lists
  • Immutable data handling
  • Signals
  • Template optimization
  • Smaller, smarter components

Once these are applied, change detection becomes predictable, faster, and scalable for complex apps.


Citations

Internal: https://savanka.com/category/savanka-helps/
External: http://angular.dev/

Leave a Comment

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 *