Slide 1

Slide 1 text

Deep dive into component
 2019/06/13 Classi Angular Night #3 
 Classi 株式会社 笠原渉

Slide 2

Slide 2 text

● 笠原 渉 (かさはら わたる)
 
 ● Classi 株式会社
 ● フロントエンドエンジニア
 ● Angular 日本ユーザー会 staff
 About me
 @kasaharu

Slide 3

Slide 3 text

Deep dive into component
 Component

Slide 4

Slide 4 text

Deep dive into component
 Component 画面の表示に欠かせない マークアップをするところ 親から子へ プロパティ受け渡す 受け取ったプロパティを 表示用に加工

Slide 5

Slide 5 text

マークアップするだけなら単純だが…
 
 - 条件によって生成 or 破棄
 - Input が与えられたら画面更新
 - イベントが発火しても画面更新 … などなど
 Deep dive into component


Slide 6

Slide 6 text

マークアップするだけなら単純だが…
 
 - 条件によって生成 or 破棄
 - Input が与えられたら画面更新
 - イベントが発火しても画面更新 … などなど
 Deep dive into component
 コンポーネントの ライフサイクル コンポーネントの変更検知

Slide 7

Slide 7 text

- コンポーネントのライフサイクルについて
 - どうやって変更検知しているか
 - パフォーマンスに優しい書き方
 目次


Slide 8

Slide 8 text

Component Lifecycle

Slide 9

Slide 9 text

Component lifecycle
 ライフサイクルメソッド知ってますか?

Slide 10

Slide 10 text

- ngOnInit : generate component すると書いてあるアレ
 
 - ngOnChanges : 入力値が変わったときの処理を書くアレ
 
 - ngOnDestroy : Observable の購読完了処理をしたりするアレ
 Component lifecycle


Slide 11

Slide 11 text

Component lifecycle
 lifecycle method ngOnChanges ngOnInit ngDoCheck ngAfterContentInit ngAfterContentChecked ngAfterViewInit ngAfterViewChecked ngOnDestroy - 8 つのメソッドがある
 - この順番で実行される


Slide 12

Slide 12 text

Component lifecycle
 lifecycle method ngOnChanges ngOnInit ngDoCheck ngAfterContentInit ngAfterContentChecked ngAfterViewInit ngAfterViewChecked ngOnDestroy - 初回は ngOnInit より先に呼ばれる
 - Input プロパティが渡されていないと呼ばれない
 - SimpleChanges 型のオブジェクトを引数で受け取 れ、今のプロパティと前のプロパティがわかる
 - firstChange フラグで初回かどうかもわかる
 入力値を使って処理をする場所

Slide 13

Slide 13 text

Component lifecycle
 lifecycle method ngOnChanges ngOnInit ngDoCheck ngAfterContentInit ngAfterContentChecked ngAfterViewInit ngAfterViewChecked ngOnDestroy - コンポーネント生成後に呼ばれる
 - Input プロパティに値がセットされた後に呼ばれる ことが保証されている
 - どんなコンポーネントも 1 回は呼ばれる
 初期化処理をする場所

Slide 14

Slide 14 text

Component lifecycle
 lifecycle method ngOnChanges ngOnInit ngDoCheck ngAfterContentInit ngAfterContentChecked ngAfterViewInit ngAfterViewChecked ngOnDestroy - 変更検知のたびに呼ばれる
 - 変更検知については後述


Slide 15

Slide 15 text

Component lifecycle
 lifecycle method ngOnChanges ngOnInit ngDoCheck ngAfterContentInit ngAfterContentChecked ngAfterViewInit ngAfterViewChecked ngOnDestroy - コンポーネント内の外部のビューに値が反映され た後に呼び出される
 - 呼び出されるのは最初の ngDoCheck の後のみ


Slide 16

Slide 16 text

Component lifecycle
 lifecycle method ngOnChanges ngOnInit ngDoCheck ngAfterContentInit ngAfterContentChecked ngAfterViewInit ngAfterViewChecked ngOnDestroy - コンポーネント内の外部のビューに値が変更され た後に呼び出される
 - 初回は ngAfterContentInit の後に、その後は ngDoCheck の後に呼ばれる


Slide 17

Slide 17 text

Component lifecycle
 lifecycle method ngOnChanges ngOnInit ngDoCheck ngAfterContentInit ngAfterContentChecked ngAfterViewInit ngAfterViewChecked ngOnDestroy - コンポーネント内のビューの値が反映されたあと に呼ばれる
 - ngAfterContentChecked の後に呼ばれる


Slide 18

Slide 18 text

Component lifecycle
 lifecycle method ngOnChanges ngOnInit ngDoCheck ngAfterContentInit ngAfterContentChecked ngAfterViewInit ngAfterViewChecked ngOnDestroy - コンポーネント内のビューの値が変更されたあと に呼ばれる
 - 初回は ngAfterViewInit の後に、その後は ngAfterContentChecked の後に呼ばれる


Slide 19

Slide 19 text

Component lifecycle
 lifecycle method ngOnChanges ngOnInit ngDoCheck ngAfterContentInit ngAfterContentChecked ngAfterViewInit ngAfterViewChecked ngOnDestroy - コンポーネントが破棄されるときに呼ばれる
 - Observable の購読解除などをやる場所


Slide 20

Slide 20 text

Component lifecycle
 lifecycle method ngOnChanges ngOnInit ngDoCheck ngAfterContentInit ngAfterContentChecked ngAfterViewInit ngAfterViewChecked ngOnDestroy - ここで再度 ngDoCheck


Slide 21

Slide 21 text

Component lifecycle
 lifecycle method ngOnChanges ngOnInit ngDoCheck ngAfterContentInit ngAfterContentChecked ngAfterViewInit ngAfterViewChecked ngOnDestroy 変更検知のたびに呼ばれる
 → ngAfterContentChecked が呼ばれる
 → ngAfterViewChecked が呼ばれる
 → コストが高い
 
 できればここで処理をしない

Slide 22

Slide 22 text

変更検知

Slide 23

Slide 23 text

- 変更検知とは?
 - JS 側で発生したイベントを Angular に伝える仕組み 
 
 - 誰が伝えているか?
 - Zone.js
 
 - 何を検知する?
 - XHRによる非同期通信、タイマー処理、クリックイベント など 
 変更検知


Slide 24

Slide 24 text

変更検知
 HomeComponent Child100Component Child300Component Child200Component Child310 Child320 Child210

Slide 25

Slide 25 text

変更検知
 HomeComponent Child100Component Child300Component Child200Component Child310 Child320 Child210 Click 検知

Slide 26

Slide 26 text

変更検知
 HomeComponent Child100Component Child300Component Child200Component Child310 Child320 Child210 ngDoCheck ngAfterContentChecked

Slide 27

Slide 27 text

変更検知
 HomeComponent Child100Component Child300Component Child200Component Child310 Child320 Child210 ngDoCheck ngAfterContentChecked

Slide 28

Slide 28 text

変更検知
 HomeComponent Child100Component Child300Component Child200Component Child310 Child320 Child210 ngDoCheck ngAfterContentChecked ngAfterViewChecked

Slide 29

Slide 29 text

変更検知
 HomeComponent Child100Component Child300Component Child200Component Child310 Child320 Child210 ngAfterViewChecked

Slide 30

Slide 30 text

変更検知
 HomeComponent Child100Component Child300Component Child200Component Child310 Child320 Child210 ngAfterViewChecked

Slide 31

Slide 31 text

変更検知
 どこかのコンポーネントで 変更検知のトリガーとなるイベントが発生 最上位のコンポーネントから順に 全てのコンポーネントで変更検知が走る

Slide 32

Slide 32 text

- フレームレートが 60fps あるとスムーズなアニメーション
 - つまり 1 フレームあたり 16msec しか使えない 
 - ref. RAIL モデル
 
 - 変更検知のたびに全てのコンポーネントを精査するとパフォーマンスに 悪い
 変更検知


Slide 33

Slide 33 text

- フレームレートが 60fps あるとスムーズなアニメーション
 - つまり 1 フレームあたり 16msec しか使えない 
 - ref. RAIL モデル
 
 - 変更検知のたびに全てのコンポーネントを精査するとパフォーマンスに 悪い
 変更検知
 ChangeDetectionStrategy

Slide 34

Slide 34 text

- ChangeDetectionStrategy
 - 変更検知についての戦略を決める 
 
 - Default
 - CheckAlways strategy : 毎回チェックする 
 - OnPush
 - CheckOnce strategy : 1 度だけチェックする 
  → Input が変わらない限りコンポーネントの状態が変化しないと判断
 変更検知


Slide 35

Slide 35 text

変更検知
 HomeComponent Child100Component Child300Component Child200Component Child310 Child320 Child210

Slide 36

Slide 36 text

- OnPush 実際にどれくらい効果があるんですか?
 変更検知


Slide 37

Slide 37 text

- OnPush 実際にどれくらい効果があるんですか?
 - angular/platform-browser の enableDebugTools を使うと計測できる 
 - ref. Developer Tools for Angular 
 変更検知


Slide 38

Slide 38 text

- enableDevTools を設定すると Chrome DevTools で計測できる
 - ng.profiler.timeChangeDetection() 
 
 - 簡単な構成でも 13msec -> 2msec くらいになる
 変更検知


Slide 39

Slide 39 text

パフォーマンスを気にしたコーディング

Slide 40

Slide 40 text

- OnPush を使うためには Input プロパティ以外でコンポーネントの状態 が変わらないように実装する必要がある
 
 - Presentational component は基本的に Input プロパティが変更された 場合のみ変更処理を必要とし、その他では変わらないようにしておくと 良い
 
 - Input プロパティが多くなると ngOnChanges の処理が膨らむ可能性が あるので getter などを使って適切に処理をわける
 パフォーマンスを意識したコーディング


Slide 41

Slide 41 text

- CheckOnce にして変更検知の回数を減らす
 - generate コマンドのオプションでも設定可能
 - $ ng g c home -c OnPush
 ChangeDetectionStrategy


Slide 42

Slide 42 text

- Input が変わる度に更新する値がある場合 ngOnChanges を使う
 - Input プロパティが増えると条件分岐が増えてくる 
 - → getter を使うとよい
 ngOnChanges


Slide 43

Slide 43 text

- Input ごとに getter を用意することで処理が複雑にならない
 - template でメソッドが呼ばれる → AfterViewChecked のたびに処理される 
 - getter に重い処理(配列操作など)があるとパフォーマンスが悪くなる 
 - → setter を使うとよい
 getter


Slide 44

Slide 44 text

- 該当の Input が変更されると setter が呼ばれる
 - template からは変更検知のたびに getter が呼ばれる 
 - 処理自体は setter にあり getter は処理済みの値を返すのみなので影響は少ない 
 setter


Slide 45

Slide 45 text

- ライフサイクルメソッドのメリット・デメリットを知る
 
 - ChangeDetectionStrategy.OnPush でパフォーマンス改善
 
 - getter, setter で実装の複雑さを減らす
 
 - enableDebugTools で計測してみる
 まとめ


Slide 46

Slide 46 text

We are Hiring!
 Classiでは一緒に働く仲間を募集しています 詳細はWantedlyページにて https://www.wantedly.com/companies/classi/projects