What is change detection in Angular and how does the OnPush strategy optimize it?
Learn how Angular change detection works and how the OnPush strategy boosts performance by skipping unchanged components using reference equality.
Expected Interview Answer
Change detection is Angular's process of checking component data bindings and updating the DOM when data changes, and the OnPush strategy optimizes it by skipping components unless their inputs change by reference, an event fires, or an async pipe emits.
By default Angular uses the CheckAlways strategy: after any event, HTTP response, or timer (tracked by Zone.js), it walks the entire component tree top to bottom checking every binding. OnPush tells Angular a component only needs checking when one of its @Input references changes, an event originates inside it, an observable bound via async pipe emits, or you manually mark it dirty. This prunes large subtrees from each cycle, dramatically reducing work in big apps, and it pairs naturally with immutable data.
- Skips unchanged subtrees, cutting checks per cycle
- Encourages immutable data patterns that are easier to reason about
- Improves performance in large component trees
- Reduces unnecessary DOM re-evaluation
- Works cleanly with the async pipe and observables
AI Mentor Explanation
Default change detection is like a scorer re-verifying every player's stats after every single ball, even players who never batted. OnPush is like agreeing to only re-check a player when their scorecard card is physically swapped for a new one. Instead of auditing the whole team each delivery, you audit just the players whose record reference changed — far less work per over while keeping the board accurate.
Step-by-Step Explanation
Step 1
Understand the default
CheckAlways walks the whole component tree after every Zone.js-tracked event, checking all bindings.
Step 2
Enable OnPush
Set changeDetection: ChangeDetectionStrategy.OnPush in the component decorator.
Step 3
Use immutable inputs
Pass new object/array references on change so OnPush detects them via reference equality.
Step 4
Bind async streams
Use the async pipe so emissions automatically mark the OnPush component for check.
Step 5
Force checks when needed
Call ChangeDetectorRef.markForCheck() for manual updates like mutated state.
What Interviewer Expects
- Explanation of the default CheckAlways cycle and Zone.js role
- The four triggers that check an OnPush component
- Why reference equality matters for @Input changes
- How the async pipe cooperates with OnPush
- When to use markForCheck or detectChanges
Common Mistakes
- Mutating input objects and expecting OnPush to update
- Thinking OnPush disables change detection entirely
- Confusing markForCheck with detectChanges
- Forgetting the async pipe already marks OnPush for check
- Assuming OnPush breaks event handling inside the component
Best Answer (HR Friendly)
“Change detection is how Angular keeps the screen in sync with the data behind it. The OnPush strategy makes this faster by only re-checking a component when its inputs actually change or an event happens inside it, so Angular skips a lot of unnecessary work in large apps.”
Code Example
@Component({
selector: 'app-user-card',
changeDetection: ChangeDetectionStrategy.OnPush,
template: `{{ user.name }}`
})
export class UserCardComponent {
@Input() user!: User;
}
// Parent must pass a NEW reference for OnPush to detect the change:
update() {
this.user = { ...this.user, name: 'New Name' }; // works
// this.user.name = 'New Name'; // ignored by OnPush
}Follow-up Questions
- What role does Zone.js play in Angular change detection?
- What is the difference between markForCheck and detectChanges?
- How does OnPush interact with the async pipe?
- Why does mutating an object break OnPush updates?
- How do Angular signals change the change-detection model?
MCQ Practice
1. Which of these triggers a check on an OnPush component?
OnPush checks when an @Input reference changes, an internal event fires, or an async pipe emits — not on unrelated events or in-place mutations.
2. What does ChangeDetectorRef.markForCheck() do?
markForCheck flags the component and its ancestors so they are checked in the next change-detection cycle.
3. Why does mutating an input object fail to update an OnPush component?
OnPush compares input references; mutating in place keeps the same reference, so Angular sees no change.
Flash Cards
What is Angular's default change detection strategy? — CheckAlways — it checks the whole component tree after every tracked event.
What are OnPush's check triggers? — Input reference change, internal event, async pipe emission, or manual markForCheck.
Why prefer immutable data with OnPush? — New references let OnPush detect changes via reference equality.
What does markForCheck do? — Marks the component and its ancestors to be checked in the next cycle.
Continue Learning
Related Interview Questions
Why does an OnPush component fail to update when you mutate an input object, and how do you fix it?
hard
What are Angular pipes and how do pure and impure pipes differ?
medium
What are Observables and how does RxJS power Angular's async handling?
medium
What is Zone.js and what role does it play in Angular change detection?
medium