コンテンツへスキップ
Angular変更検出と変更検出戦略とは

Angular変更検出と変更検出戦略とは

Angular Change Detection は、アプリの任意のコンポーネントのデータ変更を検出するためのメカニズムです。それがどのように機能し、Ignite UIでそれを有効にする方法を学びます。

6min read

Angularの最大の強みの1つは、アプリケーションの変更を簡単に検出して更新し、更新された状態を画面に自動的にレンダリングする機能です。Angular変更検出に関する誇大宣伝、Angularコンポーネント ライブラリ変更検出のしくみ、および開発者が通常実装する戦略をよりよく理解できるように、この記事では、変更検出のAngular例をいくつか示し、次のトピックについて説明します。

Try Ignite UI for Angular

Angularにおける変更検出とは何ですか?

Angular変更検出は、アプリの任意のコンポーネントでデータが変更されたときに検出し、ビューを再レンダリングするメカニズムであるため、更新された値またはオブジェクトがエンドユーザーにすぐに表示されます。このようにして、フレームワークは UI がソフトウェアの内部状態と同期し、コンポーネントとビューが常に同期していることを確認します。

変更はさまざまな機会に発生し、さまざまなイベントから派生します。

  • ネットワーク要求またはコンポーネントイベントから受信したデータ
  • マウスクリック、スクロール、マウスオーバー、キーボードナビゲーション
  • AJAX calls
  • setTimeOut、SetIntervalなどのJavaScriptタイマー関数の使用

Angularでの変更検出はどのように機能しますか?

デフォルトでは、Angularは、前述したように、ユーザーイベントまたはネットワークリクエストから受信したデータのいずれかで、アプリの変更をトリガーするたびに、Angular Grid + の他のすべてのコンポーネント (上から下へ) で変更検出を実行します。変更されたデータで DOM を検出して更新するために、フレームワークは各コンポーネントに独自の変更検出器を提供します。変更検出器は、テンプレートのバインディングを読み取り、更新されたデータをビューに反映して、データ モデルと DOM の両方が同期していることを確認します。

たとえば、データモデルをそれぞれ更新するコンポーネントバインディングを更新できます。Angular変更検出器は、トリガーされた変更を検出し、変更検出を実行して、コンポーネントツリー内のすべてのコンポーネントを上から下にチェックします。このようにして、対応するモデルが変更されたかどうかを検証します。また、新しい値の場合は、DOM を即座に更新します。

ユーザーがオンラインフォームに入力するときに「住所変更」ボタンをクリックしたとします。このアクションにより、変更検出ツリー内のすべてのビューの変更検出が自動的にトリガーされます。Angular変更ディテクターは、変更をチェックするすべてのビューを収集し、最初にこの変更を要求したユーザーの firstname プロパティの値を更新します。

Angular Change Detection Strategies

開発者として、Angularアプリが完璧に動作し、高いパフォーマンスを発揮し、優れたUXを提供するためには、さまざまな要件を満たす必要があることを私たちは知っています。インタラクティブで応答性が高く、何よりも更新されるように構築する必要があり、つまり、内部モデルの状態は常にビューと同期する必要があります。そのため、パフォーマンスを最適化したいときはいつでも、Angularでの変更検出 、データが変更されるたびに DOM を更新できます。

フレームワークが提供する 2 つのAngular変更検出戦略があります。

  • デフォルト戦略
  • OnPush strategy

Angular既定の変更検出戦略

ChangeDetector Angularデフォルトに設定されている場合、モデル プロパティの変更に対して、コンポーネント ツリーをトラバースする変更検出Angular実行して DOM を更新します。各コンポーネントには、アプリケーションの起動時に作成される変更検出器があります。

ChangeDetectorRef クラスには、変更検出ツリーの操作に使用できる組み込みメソッドがいくつか用意されています。

  • markForCheck() — コンポーネントが変更されたとマークし、更新を再度確認できるようにします。
  • detach() — 変更検出ツリーからビューを除外します。つまり、ビューが再度再アタッチされるまでチェックはトリガーされません
  • detectChanges() — ビューとその子コンポーネントをチェックします
  • checkNoChanges() — ビューとその子をチェックし、変更が検出された場合はエラーをスローします
  • reattach() — 新しい変更を検出できるように、以前にデタッチされたビューを再アタッチします。

Angular OnPush Change Detection Strategy

Angular ChangeDetector が onPush に設定されている場合、Angularは、新しい参照がコンポーネントに渡されるときにのみ変更検出器を実行します。observable が onPush に渡された場合はAngular ChangeDetector を手動で呼び出して DOM を更新する必要があります。

@Component({
     selector: 'app-card',
     templateUrl: './card.component.html',
     changeDetection: ChangeDetectionStrategy.OnPush,
     styleUrls: ['./card.component.scss'] 
     })
     export class CardComponent {
             …
        }
}

Benefits of onPush change detection

親要素が @Input() プロパティとして渡されない値を更新している場合、子コンポーネントの不要なチェックは実行されず、コンポーネントの再レンダリングが大幅に高速化されます。

Ignite UI for Angularでの変更検出の使用

Ignite UI for Angularを使用して、買い物用のアイテムのリストを表示する簡単な例を作成しましょう。買い物リストコンポーネントと、リストに新しいアイテムを追加できる入力を作成しましょう。

import { Component } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
@Component({
     selector: 'app-root',
     templateUrl: './app.component.html',
     styleUrls: ['./app.component.css']
})
export class AppComponent {
    items = new BehaviorSubject(['Apples', 'Tomatoes', 'Potatoes']);

     constructor() { }

     addNewItem(item) {
            this.items.next([...this.items, item]);
     }   
}

app.component.tsでは、いくつかのデフォルト値と、リストに新しい項目を追加するメソッドを使用してBehaviorSubjectを宣言します。

<input #newItem type="text" placeholder="Add new item"> 
<button (click)="addNewItem(newItem.value)">Add Item</button> 
<shopping-items [data]="items"></shopping-items> 

igx-list コンポーネントを使用してアイテムを表示する子コンポーネント shopping-items コンポーネントを作成します。

<h5 class="h5">Shopping List</h5>
<igx-list class="list" *ngFor="let item of shoppingItems">
    <igx-list-item class="list-item">
         <span>{{item}}</span>
     </igx-list-item>
</igx-list>
import { ChangeDetectorRef, Component, Input } from '@angular/core';
import { Observable } from 'rxjs';
@Component({
     selector: 'shopping-items',
     templateUrl: './child.component.html',
     styleUrls: ['./child.component.css']
})
export class ShoppingList {
     @Input() data: Observable<any>;
     shoppingItems: string[] = [];
     constructor(private changeDetector: ChangeDetectorRef) { }

     ngOnInit() {
         this.data.subscribe(item => {
             this.shoppingItems = [...this.shoppingItems, ...item];
             this.changeDetector.markForCheck();
         });
     }
}

ここで ChangeDetectorRef の markForCheck() メソッドを使用しない場合、Angularは変更検出の実行を拒否します。そのため、手動で行う必要があります。この方法では、特定の入力が突然変異したときに現れたときに変化検出を実行するようにAngularに指示します。

結論

プロジェクトが大きくなればなるほど、減速が大きくなります。Angular変更検出は、アプリの効率を高めるのに役立つ手法です。したがって、大規模なプロジェクトの場合は、パフォーマンスが節約されるため、ChangeDetectionStrategy.OnPushを使用することをお勧めします。

Ignite UI Angular

デモを予約