2

I'm trying to understand how ChangeDetectionStrategy.OnPush is working. On many tutorials people say that when component has OnPush strategy then component only depends on Inputs and also change detection won't happen for component's subtree is object passed to child components have the same reference.

And from my testing it works like that. But I'm wondering why modification of object is still reflected in parent components, even if they have also OnPush strategy? It looks like component is calling something like markForCheck and parent components are marked to run change detection.

But why? Isn't OnPush supposed to be used to tell that this component only depend on input properties from parent component? Why do change detection for parent component if this component is also OnPush component?

Here is my sample app. When I click changeDataImmutable then all data in sub components change because there is new object created. But when I click changeDataMutable then child components are not changed. However when I click modifyX or modifyY which mutates some deeply nested properties then this changes are still reflected in parent component (component 1). Why?

Mariusz Pawelski
  • 25,983
  • 11
  • 67
  • 80
  • 1
    See also https://stackoverflow.com/questions/42312075/change-detection-issue-why-is-this-changing-when-its-the-same-object-referen/42312239#42312239 to undestand why change dectection is triggered – yurzui Oct 09 '17 at 16:37

1 Answers1

2

But I'm wondering why modification of object is still reflected in parent components, even if they have also OnPush strategy?

It's because you use events, click in particular:

 <button (click)="changeDataImmutable()">changeDataImmutable</button>

All native events mark current component and all its ancestors for check once. Hence when Angular runs change detection for Component1 its state is checksEnabled and hence the DOM update is performed.

For the most comprehensive explanation of change detection read:

To learn more about markForCheck see this answer and read this article:

Max Koretskyi
  • 101,079
  • 60
  • 333
  • 488
  • I read you blog post before. Thanks a lot for writing this in depth articles! I'm glad that it's actually you that answered my question :) So native events marks all ancestors for checks. But what is actual purpose of that? Aren't all components checked after any async event? ( by using `NgZone` that calls `ApplicationRef.tick`) I mean when there is `Default` change detection strategy. And where Component has `OnPush` strategy I read that this component data should depend only on `Inputs` from ancestor. So why mark parent components to be checked? What's the purpose? What do we gain? – Mariusz Pawelski Oct 09 '17 at 16:21
  • @MariuszPawelski, glad you like my articles! I think you should read the articles I've posted to understand the matter. _Aren't all components checked after any async event_ - yes, but only if the state of the view (component) is `checksEnabled`. `OnPush` sets the view state to `checksDisabled` after each check. `markForCheck` switches the state to `checksEnabled` from `checksDisabled`. _So why mark parent components to be checked?_ - probably because native events bubble and so there's a potential change in parent components state. – Max Koretskyi Oct 09 '17 at 16:37