- Регистрация
- 1 Мар 2015
- Сообщения
- 1,481
- Баллы
- 155
Welcome to the Angular Daily Challenge Series, where we decode real-world Angular concepts through fun and practical coding puzzles. This article dives into a common interview-level topic: OnPush change detection in Angular.
Let's analyze today's challenge and uncover the behavior of ChangeDetectorRef and OnPush.
Angular OnPush Change Detection Challenge
Here's the scenario:
@Component({
selector: 'app-child',
template: `
<h1>Child Component</h1>
<span>{{ data().text }}</span>
`,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ChildComponent {
data = input.required<{ text: string }>();
}
@Component({
template: `
<h1>Parent Component</h1>
<app-child [data]="data" />
`,
})
export class ChangeDetectionComponent {
#cdRef = inject(ChangeDetectorRef);
data = { text: 'Hello from Parent!' };
constructor() {
setTimeout(() => {
this.data.text = 'Updated from Parent!';
// Ensure the change is visible in the OnPush child
this.#cdRef.detectChanges();
}, 3_000);
}
}
What Will Be Displayed in the Child After 3 Seconds?
Output: "Updated from Parent!"
But why does this happen? Let's break it down with a deeper look into Angular's change detection system.
? How Angular OnPush Works
When you use ChangeDetectionStrategy.OnPush, Angular skips checking the component’s template unless one of these occurs:
In our example, we changed:
this.data.text = 'Updated from Parent!';
This modifies a property of the object but doesn't change the object reference, so Angular doesn't detect this change on its own.
Hence, Angular won't rerender the child unless we force it using:
this.#cdRef.detectChanges();
This is how we manually notify Angular to run change detection for all components, including OnPush ones.
? Bonus Tip: 3_000 vs 3000 in JavaScript
You might have spotted:
setTimeout(() => { ... }, 3_000);
This is JavaScript numeric separator syntax introduced in ES2021. It’s functionally identical to 3000, but more readable.
Benefits:
Use it in modern Angular projects, it improves code clarity without affecting performance.
? Learnings Recap
? Challenge for You: Can You Optimize This?
In this challenge, we manually triggered change detection. But is that always the best approach?
? Explore These Alternatives:
? What’s your go-to strategy for handling OnPush changes? Drop your ideas and code snippets in the comments!
? Stay Connected
??? Follow for daily Angular challenges, JavaScript insights, and performance tips!
Let's analyze today's challenge and uncover the behavior of ChangeDetectorRef and OnPush.
Here's the scenario:
@Component({
selector: 'app-child',
template: `
<h1>Child Component</h1>
<span>{{ data().text }}</span>
`,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ChildComponent {
data = input.required<{ text: string }>();
}
@Component({
template: `
<h1>Parent Component</h1>
<app-child [data]="data" />
`,
})
export class ChangeDetectionComponent {
#cdRef = inject(ChangeDetectorRef);
data = { text: 'Hello from Parent!' };
constructor() {
setTimeout(() => {
this.data.text = 'Updated from Parent!';
// Ensure the change is visible in the OnPush child
this.#cdRef.detectChanges();
}, 3_000);
}
}
But why does this happen? Let's break it down with a deeper look into Angular's change detection system.
? How Angular OnPush Works
When you use ChangeDetectionStrategy.OnPush, Angular skips checking the component’s template unless one of these occurs:
- The component receives a new reference via input signal
- An event happens inside the component
- Change detection is manually triggered using ChangeDetectorRef
In our example, we changed:
this.data.text = 'Updated from Parent!';
This modifies a property of the object but doesn't change the object reference, so Angular doesn't detect this change on its own.
Hence, Angular won't rerender the child unless we force it using:
this.#cdRef.detectChanges();
This is how we manually notify Angular to run change detection for all components, including OnPush ones.
? Bonus Tip: 3_000 vs 3000 in JavaScript
You might have spotted:
setTimeout(() => { ... }, 3_000);
This is JavaScript numeric separator syntax introduced in ES2021. It’s functionally identical to 3000, but more readable.
- Easier to read large numbers (1_000_000, 3_000)
- Especially useful for time intervals, byte sizes, and money values
? Learnings Recap
| Concept | Description |
|---|---|
| ChangeDetectionStrategy.OnPush | Optimizes performance by skipping change detection unless needed |
| ChangeDetectorRef.detectChanges() | Manually triggers Angular’s change detection |
| Mutating object properties | Doesn’t trigger OnPush if the reference is unchanged |
| 3_000 in setTimeout | JavaScript numeric separator for better readability |
In this challenge, we manually triggered change detection. But is that always the best approach?
? Explore These Alternatives:
Use immutable patterns: Replace the object entirely using this.data = { text: 'Updated' }
Adopt Angular Signals (Angular 17+): Better reactivity with built-in efficiency- ? Try markForCheck() instead of detectChanges() in some cases
? What’s your go-to strategy for handling OnPush changes? Drop your ideas and code snippets in the comments!
? Stay Connected
??? Follow for daily Angular challenges, JavaScript insights, and performance tips!