Home > Web Front-end > JS Tutorial > body text

Take you to learn more about change detection in Angular

青灯夜游
Release: 2021-08-11 10:48:56
forward
2403 people have browsed it

This article will take you to learn more about change detection in Angular, and introduce to you Angular's DOM update mechanism, what problems change detection can solve, etc.

Take you to learn more about change detection in Angular

Through this article, you can help you gain this knowledge:

  • How is Angular’s ​​DOM updated? [Related tutorial recommendations: "angular tutorial"]
  • What problems does change detection solve?
  • Have a deeper understanding of change detection, familiar with its definition in Angular source code and its use in ng-zorro
  • And some personal insights

1. Angular’s ​​DOM update mechanism

Let’s first look at the simplest demo

Take you to learn more about change detection in Angular

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".

Take you to learn more about change detection in Angular

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:

  • Events: click, mouseover, mouseout, keyup, keydown, etc. all browser events
  • Timer: setTimeout, setInterval
  • XHR: various requests, etc.

Angular also provides us with a way to disable zone.js.

Take you to learn more about change detection in Angular

Take you to learn more about change detection in Angular

After disabling zone, when we click the button again, the view is not updated.

With curiosity, we found the key code of view update in Angular source code

Take you to learn more about change detection in Angular

This time we manually call this in the code method.

Take you to learn more about change detection in Angular

7-Take you to learn more about change detection in Angular

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 that DOM 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.

2. Pry into the secrets of change detection

1. Let’s start with a common Error

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

Take you to learn more about change detection in Angular

Take you to learn more about change detection in Angular

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.

Take you to learn more about change detection in Angular

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 called Change 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!

2. What is the change detection that I have been talking about for a long time?

When we change data in the model, the framework layer needs to know:

  • Where has changed in the model
  • Where in the view needs to be updated

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.

Take you to learn more about change detection in Angular

(CD is changeDetection )

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~

3. The key to the problem—Detection Sequence

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)!

<p>{{ name }}<p>
<child [name]="name"></child>
Copy after login

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.

<p>{{ name }}<p>
<child></child>
Copy after login

At this time, let’s take a look at the highly praised answers on stackoverflow. 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 = &#39;child&#39;
Copy after login

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 environment enableProdMode(), the number of change detections will be reduced from 2 to 1. This part is also described in the Angular source code.

Take you to learn more about change detection in Angular

Of course you cannot force the use of production mode in the development environment just because of this bug...

4. What everyone often calls ChangeDetectionStrategy. What is OnPush?

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, but OnPush

则是 Angular 为开发者提供的一便捷操作方式。

1Take you to learn more about change detection in Angular

用动图来表示就是:查看链接

1Take you to learn more about change detection in Angular

知名的 Angular 开源组件库 ng-zorro 就使用了大量的 OnPush 策略,这也是 Angular 性能优化的方法之一。

1Take you to learn more about change detection in Angular

三、再深入了解一些

Angular 给每个组件都关联了一份组件视图,通过 ChangeDetectorRef 可以拿到相关联的视图,在定义中我们可以看到:

export declare abstract class ChangeDetectorRef {
    abstract checkNoChanges(): void;
    abstract detach(): void;
    abstract detectChanges(): void;
    abstract markForCheck(): void;
    abstract reattach(): void;
}
Copy after login

1.detach 和 reattach

观察下面的动图,被 detached 的组件将不会被检查变更。

Take you to learn more about change detection in Angular

reattach 则可以让被 detached 的组件重新可以被检测到变更。

2.markForCheck

reattach 只会重新启用对当前组件的变更检测,但是如果父组件没有启动变更检测,那么 reattach 并不会起作用,而 markForCheck 可以很好地解决这个问题。

这一点在 ng-zorro 的源码中可以了解一二。

例如在 nz-anchor 组件中更改 nz-anchor-link 组件的 active 属性时,由于本身 ChangeDetectionStrategyOnPush ,那么就需要激活 markForCheck 来重新启用检测。具体写法可以查看 github 中的源代码。

用动图来展示则是这样,注意观察设置了 MFC 的前后变化

Take you to learn more about change detection in Angular

3.detectChanges

这个方法如同字面意思一样很好理解,就是触发一次变更检测啦,还记得本文中的第一个例子吗,我们不手动触发 tick() ,而是触发 detechtChanges() 也是可以达到效果的。

1Take you to learn more about change detection in Angular

Take you to learn more about change detection in Angular

四、最后

到这里,我相信大家已经基本弄明白了 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!

Related labels:
source:juejin.im
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template