|
| 1 | +# コンポーネントサブツリーをスキップする |
| 2 | + |
| 3 | +JavaScriptは、デフォルトでは、複数の異なるコンポーネントから参照できる可変データ構造を使用します。Angularは、データ構造の最新の状態がDOMに反映されるように、コンポーネントツリー全体で変更検知を実行します。 |
| 4 | + |
| 5 | +変更検知は、ほとんどのアプリケーションにとって十分に高速です。ただし、アプリケーションが特に大きなコンポーネントツリーを持っている場合、アプリケーション全体で変更検知を実行すると、パフォーマンスの問題が発生する可能性があります。これは、コンポーネントツリーのサブセットでのみ変更検知が実行されるように構成することで対処できます。 |
| 6 | + |
| 7 | +アプリケーションの一部が状態変化の影響を受けないと確信できる場合は、[OnPush](/api/core/ChangeDetectionStrategy)を使用して、コンポーネントのサブツリー全体の変更検知をスキップできます。 |
| 8 | + |
| 9 | +## `OnPush`の使用 |
| 10 | + |
| 11 | +OnPush変更検知は、Angularにコンポーネントのサブツリーの変更検知を次の場合**のみ**実行するように指示します。 |
| 12 | + |
| 13 | +* サブツリーのルートコンポーネントが、テンプレートバインディングの結果として新しいinputを受け取った場合。Angularは、inputの現在と過去の値を`==`で比較します。 |
| 14 | +* Angularが、OnPush変更検知を使用しているかどうかに関係なく、サブツリーのルートコンポーネント、または、その子でイベント *(例えば、イベントバインディング、outputバインディング、または`@HostListener`を使用)* を処理する場合。 |
| 15 | + |
| 16 | +コンポーネントの変更検知戦略を`@Component`デコレーターで`OnPush`に設定できます。 |
| 17 | + |
| 18 | +```ts |
| 19 | +import { ChangeDetectionStrategy, Component } from '@angular/core'; |
| 20 | +@Component({ |
| 21 | + changeDetection: ChangeDetectionStrategy.OnPush, |
| 22 | +}) |
| 23 | +export class MyComponent {} |
| 24 | +``` |
| 25 | + |
| 26 | +## 一般的な変更検知のシナリオ |
| 27 | + |
| 28 | +このセクションでは、Angularの動作を説明するために、いくつかの一般的な変更検知のシナリオを検証します。 |
| 29 | + |
| 30 | +### デフォルトの変更検知を持つコンポーネントによってイベントが処理される場合 |
| 31 | + |
| 32 | +Angularが`OnPush`戦略なしでコンポーネント内でイベントを処理する場合、フレームワークはコンポーネントツリー全体で変更検知を実行します。Angularは、新しいinputを受け取っていない、`OnPush`を使用しているルートを持つ子孫コンポーネントのサブツリーをスキップします。 |
| 33 | + |
| 34 | +例として、`MainComponent`の変更検知戦略を`OnPush`に設定し、ユーザーがルート`MainComponent`を持つサブツリーの外部のコンポーネントとやり取りする場合、`MainComponent`が新しいinputを受け取らない限り、Angularは下の図のすべてのピンク色のコンポーネント(`AppComponent`、`HeaderComponent`、`SearchComponent`、`ButtonComponent`)をチェックします: |
| 35 | + |
| 36 | +```mermaid |
| 37 | +graph TD; |
| 38 | + app[AppComponent] --- header[HeaderComponent]; |
| 39 | + app --- main["MainComponent (OnPush)"]; |
| 40 | + header --- search[SearchComponent]; |
| 41 | + header --- button[ButtonComponent]; |
| 42 | + main --- login["LoginComponent (OnPush)"]; |
| 43 | + main --- details[DetailsComponent]; |
| 44 | + event>Event] --- search |
| 45 | +
|
| 46 | +class app checkedNode |
| 47 | +class header checkedNode |
| 48 | +class button checkedNode |
| 49 | +class search checkedNode |
| 50 | +class event eventNode |
| 51 | +``` |
| 52 | + |
| 53 | +## OnPushを持つコンポーネントによってイベントが処理される場合 |
| 54 | + |
| 55 | +AngularがOnPush戦略を持つコンポーネント内でイベントを処理する場合、フレームワークはコンポーネントツリー全体で変更検知を実行します。Angularは、新しいinputを受け取っておらず、イベントを処理したコンポーネントの外部にある、OnPushを使用しているルートを持つコンポーネントのサブツリーを無視します。 |
| 56 | + |
| 57 | +例として、Angularが`MainComponent`内でイベントを処理する場合、フレームワークはコンポーネントツリー全体で変更検知を実行します。Angularは、ルートである`LoginComponent`を持つサブツリーを無視します。これは、`LoginComponent`が`OnPush`を持ち、イベントがそのスコープ外で発生したためです。 |
| 58 | + |
| 59 | +```mermaid |
| 60 | +graph TD; |
| 61 | + app[AppComponent] --- header[HeaderComponent]; |
| 62 | + app --- main["MainComponent (OnPush)"]; |
| 63 | + header --- search[SearchComponent]; |
| 64 | + header --- button[ButtonComponent]; |
| 65 | + main --- login["LoginComponent (OnPush)"]; |
| 66 | + main --- details[DetailsComponent]; |
| 67 | + event>Event] --- main |
| 68 | +
|
| 69 | +class app checkedNode |
| 70 | +class header checkedNode |
| 71 | +class button checkedNode |
| 72 | +class search checkedNode |
| 73 | +class main checkedNode |
| 74 | +class details checkedNode |
| 75 | +class event eventNode |
| 76 | +``` |
| 77 | + |
| 78 | +## OnPushを持つコンポーネントの子孫によってイベントが処理される場合 |
| 79 | + |
| 80 | +AngularがOnPushを持つコンポーネントでイベントを処理する場合、フレームワークはコンポーネントの祖先を含め、コンポーネントツリー全体で変更検知を実行します。 |
| 81 | + |
| 82 | +例として、下の図では、AngularはOnPushを使用する`LoginComponent`でイベントを処理します。Angularは、`MainComponent`に`OnPush`があるにもかかわらず、`MainComponent`(`LoginComponent`の親)を含め、コンポーネントのサブツリー全体で変更検知を呼び出します。Angularは、`LoginComponent`がそのビューの一部であるため、`MainComponent`もチェックします。 |
| 83 | + |
| 84 | +```mermaid |
| 85 | +graph TD; |
| 86 | + app[AppComponent] --- header[HeaderComponent]; |
| 87 | + app --- main["MainComponent (OnPush)"]; |
| 88 | + header --- search[SearchComponent]; |
| 89 | + header --- button[ButtonComponent]; |
| 90 | + main --- login["LoginComponent (OnPush)"]; |
| 91 | + main --- details[DetailsComponent]; |
| 92 | + event>Event] --- login |
| 93 | +
|
| 94 | +class app checkedNode |
| 95 | +class header checkedNode |
| 96 | +class button checkedNode |
| 97 | +class search checkedNode |
| 98 | +class login checkedNode |
| 99 | +class main checkedNode |
| 100 | +class details checkedNode |
| 101 | +class event eventNode |
| 102 | +``` |
| 103 | + |
| 104 | +## OnPushを持つコンポーネントへの新しいinput |
| 105 | + |
| 106 | +Angularは、テンプレートバインディングの結果としてinputプロパティを設定するときに、`OnPush`を持つ子コンポーネント内で変更検知を実行します。 |
| 107 | + |
| 108 | +例えば、下の図では、`AppComponent`は`OnPush`を持つ`MainComponent`に新しいinputを渡します。Angularは`MainComponent`で変更検知を実行しますが、`LoginComponent`も`OnPush`を持っている場合でも、新しいinputを受け取らない限り、`LoginComponent`では変更検知を実行しません。 |
| 109 | + |
| 110 | +```mermaid |
| 111 | +graph TD; |
| 112 | + app[AppComponent] --- header[HeaderComponent]; |
| 113 | + app --- main["MainComponent (OnPush)"]; |
| 114 | + header --- search[SearchComponent]; |
| 115 | + header --- button[ButtonComponent]; |
| 116 | + main --- login["LoginComponent (OnPush)"]; |
| 117 | + main --- details[DetailsComponent]; |
| 118 | + event>Parent passes new input to MainComponent] |
| 119 | +
|
| 120 | +class app checkedNode |
| 121 | +class header checkedNode |
| 122 | +class button checkedNode |
| 123 | +class search checkedNode |
| 124 | +class main checkedNode |
| 125 | +class details checkedNode |
| 126 | +class event eventNode |
| 127 | +``` |
| 128 | + |
| 129 | +## エッジケース |
| 130 | + |
| 131 | +* **TypeScriptコードでinputプロパティを変更する**。`@ViewChild`や`@ContentChild`のようなAPIを使用して、TypeScriptでコンポーネントへの参照を取得し、`@Input`プロパティを手動で変更すると、AngularはOnPushコンポーネントの変更検知を自動的に実行しません。Angularに変更検知を実行させる必要がある場合は、コンポーネントに`ChangeDetectorRef`を注入し、`changeDetectorRef.markForCheck()`を呼び出して、Angularに変更検知をスケジュールするように指示できます。 |
| 132 | +* **オブジェクト参照の変更**。inputが可変オブジェクトを値として受け取り、オブジェクトを変更しても参照を保持する場合、Angularは変更検知を呼び出しません。これは、inputの以前の値と現在の値が同じ参照を指しているため、予期される動作です。 |
0 commit comments