この記事では、Angular の変更検出について詳しく説明し、Angular の DOM 更新メカニズム、変更検出で解決できる問題などを紹介します。
この記事を通じて、次の知識を得ることができます:
最初に最も単純なデモを見てみましょう
ボタンをクリックすると、コンポーネントが変更されますname 属性の場合、変更された値もすぐに DOM に表示されます。これは少し「魔法」のように思えます。
実際の DOM の interText が要素変更ステートメントの直後に出力されるが、古い値のままであることが判明した場合、ビュー内の値はこれら 2 つのコードでは正確に何が起こっているのでしょうか?もしあなたもこのことについて疑問に思っているなら、私と一緒に答えを明らかにしましょう。
今起こったことを注意深く思い出してみましょう:
ボタンをクリックしてください
値が変わります
ネイティブ JS を使用してこのコードを記述する場合、ボタンをクリックしてもビューは変更されませんが、Angular ではビューが変更されます。 Angular を少し深く理解している場合は、zone.js というライブラリについてご存知でしょう。注意深く見てみると、zone.js は、値を変更する可能性のあるすべてのイベントに対して処理レイヤーを実行していることがわかります。 :
Angular では、zone.js を無効にする方法も提供します。
#ゾーンを無効にした後、ボタンを再度クリックしても、ビューは更新されません。 好奇心を持って、Angular ソース コードでビュー更新の 今回は、これを手動で呼び出します。コードメソッド。 まさに予想通りです!ビューが更新され、さらに驚くべきことは、印刷された innerText も更新されていることです。 ここで、DOM の更新は Nick() のトリガーに依存しており、zone.js は開発者が手動でトリガーする操作の必要性を軽減するのに役立つという結論に達しました。
さて、簡単なテストの後、Angular ビューの更新の背後で何が起こっているのかを詳しく見てみましょう。が表示されます。
ただし、このように書いても必ずしもエラーが発生するわけではありません。たとえば、子コンポーネントの input 属性を削除して更新すると、同じコードが実行できることがわかります。親コンポーネントの名前は通常通り変更できます。 えっと...考え込んでいます...おそらくあなたは、私が初めて Angular を学習し始めたとき、スタックオーバーフローでこの質問を検索していた私と同じかもしれません。 copy なぜ機能するのかわからないコードを見つけたので、直接貼り付けましたが、再びこの問題に遭遇したときは、検索とスタックオーバーフローでのコピー&ペーストを続けました...
時間が経つにつれて、さまざまな CRUD に精通しているあなたは、スタックオーバーフロー指向のプログラミングにますます不満を感じるようになり、コミュニティ、ドキュメント、フォーラムで質問に対する答えを探し始めますが、その答えや記事を読んだ後、 Change Detection というものがあることだけは知っているようですが、このバグの原因を正確に説明することはできません。私と同じ経験がある場合、深い理解がある場合は、次へ進んでください。真実を探るために!
モデル内のデータを変更するとき、フレームワーク層は次のことを知る必要があります:
誰もが React の Virtual Dom についてよく知っている必要があります。React は、DOM のすべての部分を更新するのではなく、DOM の新しい状態と古い状態を比較することによって、DOM のどの部分を更新するかを決定します。 DOM (これは Angular の変更検出でもあります。検出)。
Angular アプリケーション全体はコンポーネント ツリーです。コンポーネントの変更がすべてのコンポーネントの更新をトリガーすることは不可能です。これは非効率的で時間がかかりすぎます。たとえば、ユーザーがコンポーネントの状態を変更した場合、ボタンの場合は理想的 最良のアプローチは、アプリケーション全体を更新するのではなく、このボタンのスタイルまたはテキストのみを更新することです。これが変更検出の目的です。
デフォルト (ChangeDetectionStrategy.Default
) では、親コンポーネントの変更検出が発生すると、子コンポーネントも変更検出をトリガーします。
(CD
は changeDetection
)
変更が検出されるたびに、新しい状態と古い状態が(開発環境での) 2 つの変更検出の結果が一致しない場合は、次のようなエラーが報告されます:
#式がチェックされた後に変更されました
これは、親コンポーネントの値が子コンポーネントで変更された場合にエラーが報告される理由も説明しています。 ######しかし!前の 2 つの例では、子コンポーネントの親コンポーネントの値を変更しました。最初の例だけがエラーを報告し、2 番目の例は正常に更新できました。これらの実際の違いについても混乱している場合は、次をお読みください。 ~
#3. 問題の鍵 - 検出シーケンス##すべてのサブコンポーネントの AfterViewInit ライフサイクル フックを呼び出します
<p>{{ name }}<p> <child [name]="name"></child>
<p>{{ name }}<p> <child></child>
stackoverflow
で高く評価されている回答を見てみましょう。より明確になります。上記の検出シーケンスによると、親コンポーネントが子コンポーネントのプロパティ バインディングを行う場合、次のコードが OnChanges、OnInit、DoCheck、AfterContentInit、AfterViewInit のいずれかのライフ サイクル フックで実行されるかどうかに関係なく、エラーが報告されます。this.parentCmpt.name = 'child'
enableProdMode()、変更検出の数は 2 から 1 に減ります。この部分は Angular ソース コード
でも説明されています。もちろん、このバグのためだけに開発環境で実稼働モードの使用を強制することはできません...
4.多くの場合、ChangeDetectionStrategy が呼び出されます。
则是 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
更多编程相关知识,请访问:编程入门!!
以上がAngular での変更検出について詳しく学びましょうの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。