Angular開発実践(五):変化モニタリングを深く解析する
5924 ワード
変化モニタリングとは
Angularを使用した開発では、モデルからビューへの入力バインディング、ビューからモデルへの出力バインディング、およびビューとモデルの双方向バインディングなど、Angularへのバインディングによく使用されます.これらのバインド値がビューとモデルの間で同期を保つことができるのは,Angularにおける変化検出のおかげである.
簡単に言えば、変化検出とは、Angularがビューとモデルの間のバインド値が変化したかどうかを検出するために使用し、モデル内のバインド値が変化したことを検出すると、ビューに同期し、逆に、ビュー上のバインド値が変化したことを検出すると、対応するバインド関数がコールバックされる.
変化モニタリングのソース
変化モニタリングの鍵は、バインドされた値が変化したかどうかをどのように最小粒度でモニタリングするかであり、どのような場合にこれらのバインドされた値が変化するのでしょうか.私たちがよく使ういくつかのシーンを見てみましょう.
Events: click/hover/...
@Component({
selector: 'demo-component',
template: `
{{name}}
`
})
export class DemoComponent {
name: string = 'Tom';
changeName() {
this.name = 'Jerry';
}
}
テンプレートでは、補間式によってnameプロパティをバインドします.
change name
をクリックするとname属性の値が変更され、テンプレートビュー表示内容も変更される.XHR/webSocket
@Component({
selector: 'demo-component',
template: `
{{name}}
`
})
export class DemoComponent implements OnInit {
name: string = 'Tom';
constructor(public http: HttpClient) {}
ngOnInit() {
// ./getNewName , 'Jerry'
this.http.get('./getNewName').subscribe((data: string) => {
this.name = data;
});
}
}
このコンポーネントのngOnInit関数でサーバ側にAjaxリクエストを送信しました.このリクエストが結果を返すと、現在のテンプレートビューでバインドされているname属性の値も変更されます.
Times: setTimeout/requestAnimationFrame
@Component({
selector: 'demo-component',
template: `
{{name}}
`
})
export class DemoComponent implements OnInit {
name: string = 'Tom';
constructor() {}
ngOnInit() {
// ./getNewName , 'Jerry'
setTimeout(() => {
this.name = 'Jerry';
}, 1000);
}
}
このコンポーネントのngOnInit関数では、タイミングタスクを設定することで、タイミングタスクが実行されると、現在のビューにバインドされているname属性の値も変更されます.
まとめ
変化モニタリングの処理メカニズム
以上より,変化検出がどのようにトリガされるかを大まかに理解したが,Angularにおける変化モニタリングはどのように行われるのか.
まず、各コンポーネントに対して、対応する変化モニタがあることを知る必要があります.すなわち,各Componentには
changeDetector
が対応しており,Componentでは依存注入によりchangeDetector
を得ることができる.一方,我々の複数のComponentは木構造の組織であり,1つのComponentが
changeDetector
に対応するため,changeDetector
間は同様に木構造の組織である.最後に覚えておきたいのは、変化モニタリングのたびにComponentの木の根から始まることです.
例を挙げる
サブアセンブリ:
@Component({
selector: 'demo-child',
template: `
{{title}}
{{paramOne}}
{{paramTwo}}
`
})
export class DemoChildComponent {
title: string = ' ';
@Input() paramOne: any; // 1
@Input() paramTwo: any; // 2
}
親コンポーネント:
@Component({
selector: 'demo-parent',
template: `
{{title}}
`
})
export class DemoParentComponent {
title: string = ' ';
paramOneVal: any = ' paramOne ';
paramTwoVal: any = ' paramTwo ';
changeVal() {
this.paramOneVal = ' paramOne ';
}
}
上のコードでは、DemoParentComponentはDemoChildComponentにラベルで埋め込まれており、ツリー構造上、DemoParentComponentはDemoChildComponentのルートノードであり、DemoChildComponentはDemoParentComponentのリーフノードである.
DemoParentComponentのbuttonをクリックすると、changeValメソッドにコールバックされ、変更モニタリングの実行がトリガーされます.変更モニタリングの流れは次のとおりです.
まず、変化検出はDemoParentComponentから開始します.
変化モニタリングポリシー
変化モニタリングの処理メカニズムを学んだ後、このメカニズムは少し簡単で乱暴ではないかと思うかもしれません.もし私のアプリケーションに何百人ものComponentがあり、任意のComponentがモニタリングをトリガーしたら、ルートノードからリーフノードまで再検出する必要があります.
焦らないで、Angularの開発チームはすでにこの問題を考慮して、上述の検出メカニズムはただ1種のデフォルトの検出メカニズムで、Angularはまた1種のOnPushの検出メカニズム(メタデータ属性changeDetection:ChangeDetectionStrategy.OnPushを設定する)を提供します.
OnPushとDefaultの違い:サブコンポーネント入力にバインドされた値が変化していないことが検出された場合、変化検出はサブコンポーネントに深く入り込まない.
変更モニタクラス-ChangeDetectorRef
前述したように、コンポーネントメタデータ属性changeDetectionを変更して、コンポーネントの変化モニタリングポリシー(ChangeDetectionStrategy.DefaultまたはChangeDetectionStrategy.OnPush)を変更することができます.また、ChangeDetectorRefを使用して、コンポーネントの変化モニタリングをより柔軟に制御することもできます.
Angularは、実行中に各コンポーネントに対してChangeDetectorRefのインスタンスを作成します.このインスタンスは、変更モニタリングを手動で管理する方法を提供します.このクラスでは、変更モニタリングの停止/有効化、または指定されたパスによる変更モニタリングなど、コンポーネントの変更モニタリングポリシーをカスタマイズできます.
関連方法は次のとおりです.
使用方法も簡単で、コンポーネントに直接注入すればいいです.
@Component({
selector: 'demo-parent',
template: `
{{title}}
`
})
export class DemoParentComponent implements OnInit {
title: string = ' ';
constructor(public cdRef: ChangeDetectorRef) {}
ngOnInit() {
this.cdRef.detach(); // ,
}
}