On the road to Fine-Grained Change Detection
thomas
Posted on November 1, 2023
A pull request was recently merged and will be available in the upcoming major version v17. This pull request represents the first step towards fine-grained reactivity and signal-based components.
If you want to read more, click the pull request below:
perf(core): Update LView consumer to only mark component for check #52302
This commit updates the reactive template and host binding consumers to only mark their declaration components for refresh, but not parents/ancestors.
This also updates the AfterViewChecked
hook to run when a component is refreshed during change detection but its host is not. It is reasonable to expect that the ngAfterViewChecked
lifecycle hook will run when a signal updates and the component is refreshed. The hooks are typically run when the host is refreshed so without this change, the update to not mark ancestors dirty would have caused ngAfterViewChecked
to not run.
resolves #14628 resolves #22646
resolves #34347 - this is not the direct request of the issue but generally forcing change detection to run is necessary only because a value was updated that needs to be synced to the DOM. Values that use signals will mark the component for check automatically so accessing the ChangeDetectorRef
of a child is not necessary. The other part of this request was to avoid the need to "mark all views for checking since it wouldn't affect anything but itself". This is directly addressed by this PR - updating a signal that's read in the child view's template will not cause ancestors/"all views" to be refreshed.
The goal of this change is to refresh ONLY the component where the change occurred, but there are a couple of requirements:
- All your components need to use OnPush.
- The change has to be triggered by a Signal.
Let's take a step back and explain why we need OnPush and Signals to benefit from local change detection.
How Change Detection Works
Angular employs Zone.js to detect changes and trigger a new render. Since Zone.js doesn't track where a change occurred, Angular performs a top-to-bottom rerender. This means that Angular refreshes the RootComponent down to all ChildComponents. This operation is fast but costly since Angular rerenders all components even if only a small change occurred.
Meanwhile, ChangeDetectionStrategy.OnPush was introduced to optimize the change detection cycle. When a component is marked for check, all its ancestors are also marked for check. Then Angular triggers a top-down cycle and only refreshes the marked components.
In v16, Angular introduced Signals, a new reactive API. This API allows Angular to precisely determine where a change is occurring. Angular can now identify which components need to be refreshed. A Signal marks the component as dirty but not its ancestors. When Angular performs its top-down change detection cycle, only that specific component will be refreshed.
Notes:
- Angular still needs to perform a top-down change detection to maintain backward compatibility with previous versions and with components not using Signals, relying on Zone.js instead.
- Currently, Angular cannot achieve more granularity than per-component because it might disrupt how non-signal components are refreshed. In the future, the goal is to be more granular, but it will never be as granular as the binding. Refer to the RFC for more details.
Conclusion:
Now you should understand why this change will benefit applications that leverage the use of Signals and OnPush.
- Signals allow Angular to precisely pinpoint where the change occurred and mark only the affected component as dirty.
- OnPush is necessary because Angular still requires a top-down change detection, and it only refreshes OnPush components when marked for check. All Default components will still be rerefreshed.
Update your application to v17 and start using Signals, as this is just the beginning of how Signals can enhance your Angular application.
You can find me on Twitter or Github.Don't hesitate to reach out to me if you have any questions.
Thanks to Enea for reviewing it.
Posted on November 1, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.