This article will take you to learn more about change detection inAngular, and introduce to you Angular's DOM update mechanism, what problems change detection can solve, etc.
Through this article, you can help you gain this knowledge:
Let’s first look at the simplest demo
When the button is clicked, we change the component For the name attribute, the changed value is also displayed in the DOM in just a moment, which seems a bit "magical".
If the innterText in the real DOM is printed out immediately after the element change statement, but it is found that it is still the old value, but the value in the view has obviously changed. What exactly is happening in these two pieces of code? If you are also wondering about this, then join me to reveal the answer.
Let’s carefully recall what just happened:
Click the button
The value changes
If you use native JS to write this code, the view will definitely not change after clicking the button, but in Angular, the view will change. If you have a slightly in-depth understanding of Angular, you will know about a library called zone.js. If you look carefully, you will find that zone.js does a layer of processing for all events that may change values, such as:
Angular also provides us with a way to disable zone.js.
After disabling zone, when we click the button again, the view is not updated.
With curiosity, we found thekey code of view update in Angular source code
This time we manually call this in the code method.
It’s exactly as expected! The view is updated, and what’s even more surprising is that the printed innerText is also updated!
Here, we have come to the conclusion thatDOM updates depend on the triggering of tick(), and zone.js helps developers save the need for manual triggering operations.
Okay, after a small test, let's take a closer look at what happens behind the Angular view update.
Let’s look at it first Such an error occurs when the name value of the parent component parent is changed in the ngOnInit of the child component. As a result, the error message that everyone must have encountered appears
But writing this way does not always result in an error. For example, if we remove the input attribute of the child component, refresh it, and find that the same code can run, and the name of the parent component can be changed normally.
emmm... Lost in thought...
Maybe you are like me when I first started learning Angular, searching for this question in stackoverflow, copy I found a code that I didn’t know why it worked, so I pasted it directly. When I encountered this problem again, I continued to search and copy and paste in stackoverflow, and so on...
As time goes by, you who are proficient in various CRUD are increasingly dissatisfied with stackoverflow-oriented programming. You start to look for answers to questions in communities, documents, and forums, but after reading their From the answers and articles, it seems that I only know that there is something calledChange Detection, but I can’t explain exactly what caused this bug. If you have the same experience as me, If you have a deep understanding, then continue to explore the truth!
When we change data in the model, the framework layer needs to know:
Everyone must be familiar with the Virtual Dom in React. React determines which part of the DOM to update by comparing the new state and the old state of the DOM, instead of updating all the DOM. This is also the change detection in Angular. detection).
The entire Angular application is a component tree. It is impossible for changes in any component to trigger the update of all components. This is too inefficient and time-consuming. For example, if the user changes the state of a button, then the ideal The best approach is to update only the style or text of this button instead of updating the entire application. This is the purpose of change detection.
By default (ChangeDetectionStrategy.Default
), when the change detection of the parent component occurs, the child component will also trigger change detection.
(CD
ischangeDetection
)
Every time a change is detected, the new and old states will be compared. If the results of the two change detections (in the development environment) are inconsistent, an error will be reported, for example:
Expression has changed after it was checked
This also explains why If the value of the parent component is changed in the child component, an error will be reported.
but! In the previous two examples, we changed the value of the parent component in the child component. Only the first one reported an error, and the second one could be updated normally. If you are also confused about the real difference between them, Then read on~
First come to the conclusion:
Update the binding properties of all subcomponents
Call the OnChanges, OnInit, DoCheck, AfterContentInit life cycle hooks of all subcomponents
Update the current Component's DOM
Subcomponent triggers change detection
Calls the AfterViewInit life cycle hook of all subcomponents
We don’t focus on too fine details here (don’t wonder why it is in this order, just remember that this is how it is set up in Angular). If anyone wants to talk about Angular’s design in this part Feel free to leave a message in the comment area to discuss~)
In the first example, the parent component parent passes the input attribute name to the child component, and the child component updates the name attribute of the parent component in ngOnInit. In other words, this code ** violates the detection sequence (** operates the first step in the second step of the sequence)!
{{ name }}
In the second example, even if the child component also updates the name attribute of the parent component in ngOnInit, but because the parent component parent does not bind the input attribute name to the child component child, it will not appear. and violate the change detection queue order, so it can run normally.
{{ name }}
At this time, let’s take a look at the highly praised answers onstackoverflow. It will be much clearer. According to the above detection sequence, we will find that as long as the parent component does the child component Property binding, no matter whether the following code is executed in any of the life cycle hooks of OnChanges, OnInit, DoCheck, AfterContentInit and AfterViewInit, an error will be reported.
this.parentCmpt.name = 'child'
Okay, now we have understood the real reason why this error occurs, but I still want to remind you that this error will only be triggered in the development environment, and will be called in the production environmentenableProdMode()
, the number of change detections will be reduced from 2 to 1. This part is also described in theAngular source code.
Of course you cannot force the use of production mode in the development environment just because of this bug...
ChangeDetectionStrategy
The default is Default, that is, the CD of the parent component will trigger the CD of the child component, but obviously in some cases we can judge by ourselves that some child components are in the parent component. Component CD does not need to be triggered, butOnPush
则是 Angular 为开发者提供的一便捷操作方式。
用动图来表示就是:查看链接
知名的 Angular 开源组件库 ng-zorro 就使用了大量的 OnPush 策略,这也是 Angular 性能优化的方法之一。
Angular 给每个组件都关联了一份组件视图,通过ChangeDetectorRef
可以拿到相关联的视图,在定义中我们可以看到:
export declare abstract class ChangeDetectorRef { abstract checkNoChanges(): void; abstract detach(): void; abstract detectChanges(): void; abstract markForCheck(): void; abstract reattach(): void; }
观察下面的动图,被detached
的组件将不会被检查变更。
而reattach
则可以让被detached
的组件重新可以被检测到变更。
reattach
只会重新启用对当前组件的变更检测,但是如果父组件没有启动变更检测,那么reattach
并不会起作用,而markForCheck
可以很好地解决这个问题。
这一点在 ng-zorro 的源码中可以了解一二。
例如在 nz-anchor 组件中更改 nz-anchor-link 组件的 active 属性时,由于本身ChangeDetectionStrategy
为OnPush
,那么就需要激活 markForCheck 来重新启用检测。具体写法可以查看 github 中的源代码。
用动图来展示则是这样,注意观察设置了 MFC 的前后变化
这个方法如同字面意思一样很好理解,就是触发一次变更检测啦,还记得本文中的第一个例子吗,我们不手动触发tick()
,而是触发detechtChanges()
也是可以达到效果的。
到这里,我相信大家已经基本弄明白了 Angular 变更检测,如果有任何疑问,欢迎在评论区交流讨论~
在撰写这篇文章时,笔者参(fu)考(zhi)了大量的社区文章和讨论,一方面是感慨如此重要的概念在 Angular 中文社区中却只有零星几篇相关介绍的文章,另一方面是看到了虽然国内 Angular 开发者虽然数量远少于 React 和 Vue,却依然非常热情的贡献自己的知识和见解来为 Angular 中文社区添砖加瓦,作为已使用 Angular 半年多的开发者,深深感受到 Google 的工程美学。
大而全且不失优雅,是笔者对 Angular 这款 Web 框架的最大感受,感谢开源社区中的各位开发者们~
对于文中描述错误的地方,还望大佬们批评斧正~
原文地址:https://juejin.cn/post/6844904079878012935
作者:LangWalker
更多编程相关知识,请访问:编程入门!!
The above is the detailed content of Take you to learn more about change detection in Angular. For more information, please follow other related articles on the PHP Chinese website!