How does Angular OnPush change detection affect rendering?

This tests change detection tree knowledge. OnPush skips checks unless inputs change by reference, events fire, or async pipes mark for check. Mutated objects or manual subscriptions without markForCheck cause silent misses.
WHAT THIS TESTS: Whether you understand Angular's unidirectional data flow and the conditions that trigger change detection in an OnPush subtree. Interviewers want to see that you know OnPush is not just a performance decorator but a contract about immutability and explicit signaling.
A GOOD ANSWER COVERS: First, the three ways Angular checks an OnPush component: when an input property receives a new object reference, when a bound DOM event originates inside the component, or when an async pipe or manual call to ChangeDetectorRef.markForCheck notifies the view. Second, that OnPush skips the default top-down check for that branch, which means child components also inherit the strategy unless overridden. Third, the observable pitfall: if you subscribe manually in ngOnInit and store the value in a local property, the view will not refresh unless you also call markForCheck or use the async pipe in the template, because the subscription callback runs outside Angular's zone awareness for that component. Fourth, that mutating an array or object in place without creating a new reference causes a silent stale view.
COMMON WRONG ANSWERS: Claiming OnPush simply makes the app faster with no downsides. Saying Angular never checks OnPush components, rather than explaining the specific trigger conditions. Suggesting setTimeout or setInterval automatically fixes OnPush misses without mentioning zone.js configuration or manual marking. Proposing deep comparison of inputs as a solution, which defeats the performance purpose. Ignoring that child components of an OnPush parent are affected by the parent's strategy.
LIKELY FOLLOW-UPS: How would you design a large application with OnPush at every level? What is the difference between markForCheck and detectChanges? When would you use a signal-based component instead of OnPush with observables? How does zone.js interact with OnPush, and what happens if you run outside NgZone?
ONE CONCRETE EXAMPLE: Imagine a parent passes an array of users into an OnPush child via an input. The child displays the list. If the parent pushes a new user into the existing array instead of assigning a new array reference, the child never re-renders. To fix it, the parent should create a new array with the spread operator. Alternatively, if the child subscribes to a userStore observable directly in TypeScript, the template stays blank until the subscription emits, but after the first emit, further emissions do not update the view. The fix is to bind the observable directly in the template with the async pipe, which internally calls markForCheck, or to inject ChangeDetectorRef and call markForCheck inside the subscription callback.
Read the original → angular.dev
Get five bites like this every day.
Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.