Angular での変更検出について詳しく学びましょう

青灯夜游
リリース: 2021-08-11 10:48:56
転載
2410 人が閲覧しました

この記事では、Angular の変更検出について詳しく説明し、Angular の DOM 更新メカニズム、変更検出で解決できる問題などを紹介します。

Angular での変更検出について詳しく学びましょう

この記事を通じて、次の知識を得ることができます:

  • Angular の DOM はどのように更新されますか? [関連チュートリアルの推奨事項: "angular チュートリアル"]
  • 変更検出はどのような問題を解決しますか?
  • 変更検出についてより深く理解し、Angular ソース コードでのその定義と ng-zorro での使用方法に精通している
  • およびいくつかの個人的な洞察

1. Angular の DOM 更新メカニズム

最初に最も単純なデモを見てみましょう

Angular での変更検出について詳しく学びましょう

ボタンをクリックすると、コンポーネントが変更されますname 属性の場合、変更された値もすぐに DOM に表示されます。これは少し「魔法」のように思えます。

Angular での変更検出について詳しく学びましょう

実際の DOM の interText が要素変更ステートメントの直後に出力されるが、古い値のままであることが判明した場合、ビュー内の値はこれら 2 つのコードでは正確に何が起こっているのでしょうか?もしあなたもこのことについて疑問に思っているなら、私と一緒に答えを明らかにしましょう。

今起こったことを注意深く思い出してみましょう:

  • ボタンをクリックしてください

  • 値が変わります

ネイティブ JS を使用してこのコードを記述する場合、ボタンをクリックしてもビューは変更されませんが、Angular ではビューが変更されます。 Angular を少し深く理解している場合は、zone.js というライブラリについてご存知でしょう。注意深く見てみると、zone.js は、値を変更する可能性のあるすべてのイベントに対して処理レイヤーを実行していることがわかります。 :

  • イベント: クリック、マウスオーバー、マウスアウト、キーアップ、キーダウンなどのすべてのブラウザ イベント
  • タイマー: setTimeout、setInterval
  • XHR: さまざまなリクエストなど.

Angular では、zone.js を無効にする方法も提供します。

Angular での変更検出について詳しく学びましょう

Angular での変更検出について詳しく学びましょう

#ゾーンを無効にした後、ボタンを再度クリックしても、ビューは更新されません。

好奇心を持って、Angular ソース コードでビュー更新の

主要なコードを見つけました。

Angular での変更検出について詳しく学びましょう

今回は、これを手動で呼び出します。コードメソッド。

Angular での変更検出について詳しく学びましょう

7-Angular での変更検出について詳しく学びましょう

まさに予想通りです!ビューが更新され、さらに驚くべきことは、印刷された innerText も更新されていることです。

ここで、

DOM の更新は Nick() のトリガーに依存しており、zone.js は開発者が手動でトリガーする操作の必要性を軽減するのに役立つという結論に達しました

さて、簡単なテストの後、Angular ビューの更新の背後で何が起こっているのかを詳しく見てみましょう。

2. 変更検出の秘密を探る

1. よくあるエラーから始めましょう

見てみましょうこのようなエラーは、子コンポーネントの ngOnInit で親コンポーネントの name 値が変更されると発生し、その結果、誰もが遭遇したであろうエラー メッセージ

Angular での変更検出について詳しく学びましょう が表示されます。

Angular での変更検出について詳しく学びましょう

ただし、このように書いても必ずしもエラーが発生するわけではありません。たとえば、子コンポーネントの input 属性を削除して更新すると、同じコードが実行できることがわかります。親コンポーネントの名前は通常通り変更できます。

Angular での変更検出について詳しく学びましょう

えっと...考え込んでいます...

おそらくあなたは、私が初めて Angular を学習し始めたとき、スタックオーバーフローでこの質問を検索していた私と同じかもしれません。 copy なぜ機能するのかわからないコードを見つけたので、直接貼り付けましたが、再びこの問題に遭遇したときは、検索とスタックオーバーフローでのコピー&ペーストを続けました...

時間が経つにつれて、さまざまな CRUD に精通しているあなたは、スタックオーバーフロー指向のプログラミングにますます不満を感じるようになり、コミュニティ、ドキュメント、フォーラムで質問に対する答えを探し始めますが、その答えや記事を読んだ後、 Change Detection というものがあることだけは知っているようですが、このバグの原因を正確に説明することはできません。私と同じ経験がある場合、深い理解がある場合は、次へ進んでください。真実を探るために!

2. 私が長い間話してきた変化検出とは何ですか?

モデル内のデータを変更するとき、フレームワーク層は次のことを知る必要があります:

  • モデルのどこが変更されたか
  • ビューのどこが変更されたかを知る必要があります。更新される

誰もが React の Virtual Dom についてよく知っている必要があります。React は、DOM のすべての部分を更新するのではなく、DOM の新しい状態と古い状態を比較することによって、DOM のどの部分を更新するかを決定します。 DOM (これは Angular の変更検出でもあります。検出)。

Angular アプリケーション全体はコンポーネント ツリーです。コンポーネントの変更がすべてのコンポーネントの更新をトリガーすることは不可能です。これは非効率的で時間がかかりすぎます。たとえば、ユーザーがコンポーネントの状態を変更した場合、ボタンの場合は理想的 最良のアプローチは、アプリケーション全体を更新するのではなく、このボタンのスタイルまたはテキストのみを更新することです。これが変更検出の目的です。

デフォルト (ChangeDetectionStrategy.Default) では、親コンポーネントの変更検出が発生すると、子コンポーネントも変更検出をトリガーします。

Angular での変更検出について詳しく学びましょう

(CDchangeDetection )

変更が検出されるたびに、新しい状態と古い状態が(開発環境での) 2 つの変更検出の結果が一致しない場合は、次のようなエラーが報告されます:

#式がチェックされた後に変更されました

これは、親コンポーネントの値が子コンポーネントで変更された場合にエラーが報告される理由も説明しています。 ######しかし!前の 2 つの例では、子コンポーネントの親コンポーネントの値を変更しました。最初の例だけがエラーを報告し、2 番目の例は正常に更新できました。これらの実際の違いについても混乱している場合は、次をお読みください。 ~

#3. 問題の鍵 - 検出シーケンス

#まず結論を出します:

    Update theすべてのサブコンポーネントのバインディング プロパティ
  • すべてのサブコンポーネントの OnChanges、OnInit、DoCheck、AfterContentInit ライフ サイクル フックを呼び出します
  • 現在のコンポーネントの DOM# を更新します
  • サブコンポーネントは変更検出をトリガーします
  • ##すべてのサブコンポーネントの AfterViewInit ライフサイクル フックを呼び出します

  • ##ここではあまり細かい点に焦点を当てないでください (なぜこの順序になっているのか不思議ではありませんが、これが Angular での設定方法であることを覚えておいてください)。この部分で Angular の設計について話したい人がいたら、遠慮なく言ってください。コメント領域にメッセージを残して議論してください~)

    最初の例では、親コンポーネントの親が入力属性名を子コンポーネントに渡し、子コンポーネントが ngOnInit で親コンポーネントの name 属性を更新します。言い換えると、このコードは ** 検出シーケンスに違反しています (** はシーケンスの 2 番目のステップで最初のステップを実行します)。
  • <p>{{ name }}<p>
    <child [name]="name"></child>
    ログイン後にコピー
2 番目の例では、子コンポーネントが ngOnInit で親コンポーネントの name 属性も更新する場合でも、親コンポーネントの親が入力属性名を子コンポーネントの子にバインドしていないため、表示されず、変更検出キューの順序に違反しているため、正常に実行できます。

<p>{{ name }}<p>
<child></child>
ログイン後にコピー

この時点で、

stackoverflow

で高く評価されている回答を見てみましょう。より明確になります。上記の検出シーケンスによると、親コンポーネントが子コンポーネントのプロパティ バインディングを行う場合、次のコードが OnChanges、OnInit、DoCheck、AfterContentInit、AfterViewInit のいずれかのライフ サイクル フックで実行されるかどうかに関係なく、エラーが報告されます。

this.parentCmpt.name = &#39;child&#39;
ログイン後にコピー

さて、このエラーが発生する本当の理由は理解できましたが、このエラーは開発環境でのみトリガーされ、運用環境で呼び出されるということを思い出していただきたい

enableProdMode()、変更検出の数は 2 から 1 に減ります。この部分は Angular ソース コード

でも説明されています。

もちろん、このバグのためだけに開発環境で実稼働モードの使用を強制することはできません...

Angular での変更検出について詳しく学びましょう4.多くの場合、ChangeDetectionStrategy が呼び出されます。

ChangeDetectionStrategy デフォルトは Default です。つまり、親コンポーネントの CD が子コンポーネントの CD をトリガーしますが、明らかに、場合によっては自分で判断できる場合があります。一部の子コンポーネントは親コンポーネント内にあります。コンポーネント CD をトリガーする必要はありませんが、OnPush

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

1Angular での変更検出について詳しく学びましょう

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

1Angular での変更検出について詳しく学びましょう

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

1Angular での変更検出について詳しく学びましょう

三、再深入了解一些

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

export declare abstract class ChangeDetectorRef {
    abstract checkNoChanges(): void;
    abstract detach(): void;
    abstract detectChanges(): void;
    abstract markForCheck(): void;
    abstract reattach(): void;
}
ログイン後にコピー

1.detach 和 reattach

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

Angular での変更検出について詳しく学びましょう

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

2.markForCheck

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

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

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

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

Angular での変更検出について詳しく学びましょう

3.detectChanges

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

1Angular での変更検出について詳しく学びましょう

Angular での変更検出について詳しく学びましょう

四、最后

到这里,我相信大家已经基本弄明白了 Angular 变更检测,如果有任何疑问,欢迎在评论区交流讨论~

在撰写这篇文章时,笔者参(fu)考(zhi)了大量的社区文章和讨论,一方面是感慨如此重要的概念在 Angular 中文社区中却只有零星几篇相关介绍的文章,另一方面是看到了虽然国内 Angular 开发者虽然数量远少于 React 和 Vue,却依然非常热情的贡献自己的知识和见解来为 Angular 中文社区添砖加瓦,作为已使用 Angular 半年多的开发者,深深感受到 Google 的工程美学。

大而全且不失优雅,是笔者对 Angular 这款 Web 框架的最大感受,感谢开源社区中的各位开发者们~

对于文中描述错误的地方,还望大佬们批评斧正~

原文地址:https://juejin.cn/post/6844904079878012935

作者:LangWalker

更多编程相关知识,请访问:编程入门!!

以上がAngular での変更検出について詳しく学びましょうの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:juejin.im
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート