Change detection is one of the most powerful—but also most misunderstood—systems in Angular. When not optimized correctly, it can slow down rendering, cause unnecessary re-renders, affect scrolling, block user interactions, and degrade your overall UX.
This guide explains why change detection becomes slow and how to fix it with proven techniques.
1. What Causes Slow Change Detection?
Angular’s default strategy checks an entire component tree whenever something triggers a change such as:
- API responses
- Event handlers
- Timers (setTimeout / setInterval)
- Form updates
- Observable emissions
- Parent-child property changes
On large pages, this causes:
- laggy rendering
- slow scrolling
- visible UI delays
- inefficient loops
This happens because Angular uses the Default Change Detection Strategy, which checks every binding on every event.
2. Fix #1: Use OnPush Change Detection
Switching to ChangeDetectionStrategy.OnPush tells Angular:
“Re-check this component ONLY when necessary.”
How to apply:
import { Component, ChangeDetectionStrategy } from '@angular/core';
@Component({
selector: 'app-users',
templateUrl: './users.component.html',
changeDetection: ChangeDetectionStrategy.OnPush
})
export class UsersComponent {
users = [];
}
Benefits:
- Fewer checks
- Faster UI updates
- Better performance in large lists
- Works perfectly with Observables & Signals
*3. Fix #2: Use trackBy in ngFor
A huge performance mistake is:
<div *ngFor="let user of users">
Angular re-renders every item even if only one changed.
Correct version with trackBy:
<div *ngFor="let user of users; trackBy: trackByUser">
trackByUser(index: number, user: any) {
return user.id;
}
Result:
- Only changed rows re-render
- Great for tables, lists, feeds
4. Fix #3: Replace Imperative Logic with Signals or Observables
Signals make change detection more predictable:
import { signal } from '@angular/core';
count = signal(0);
increase() {
this.count.update(c => c + 1);
}
Signals update only what needs updating, not the whole view tree.
5. Fix #4: Avoid Heavy Work Inside Templates
❌ Bad:
{{ calculateSomething(bigArray) }}
This runs every cycle.
✔ Correct:
result = this.calculateSomething(bigArray);
Then use:
{{ result }}
6. Fix #5: Use Detach for Super-Complex Components
For extremely heavy components:
constructor(private cd: ChangeDetectorRef) {}
ngOnInit() {
this.cd.detach();
}
Then manually trigger:
this.cd.detectChanges();
This gives full control over when Angular updates the component.
7. Fix #6: Avoid Multiple Async Subscriptions
Multiple nested subscriptions cause excessive updates.
❌ Bad:
service.getA().subscribe(a => {
service.getB().subscribe(b => {
...
});
});
✔ Fix using combineLatest:
combineLatest([service.getA(), service.getB()])
.subscribe(([a, b]) => {...});
8. Fix #7: Limit DOM Size & Break Large Components
If your component template contains:
- large tables
- infinite loops
- 1000+ DOM nodes
Angular change detection will lag.
Solution:
- Break into smaller components
- Use pagination
- Virtual scrolling
- Lazy loading of sub-components
9. Quick Checklist to Fix Change Detection Issues
| Issue | Fix |
|---|---|
| UI lag | Switch to OnPush |
| Large list rendering slow | Add trackBy |
| Too many subscriptions | Use combineLatest |
| template calling heavy functions | Move logic to TS file |
| signals not used | Use signal for reactive UI |
| Large component | Split into child components |
| SSR hydration slow | Reduce initial DOM load |
Conclusion
Fixing Angular change detection is mainly about:
- Updating only what needs updating
- Reducing unnecessary checks
- Using OnPush, trackBy, and signals
- Structuring components efficiently
With these techniques, your Angular performance improves instantly — especially on large apps.
Citations
Internal: https://savanka.com/category/savanka-helps/
External: http://angular.dev/