WEBVTT

1
00:00:00.000 --> 00:00:00.903
こんにちは。

2
00:00:00.903 --> 00:00:02.859
リアクト入門の第五回です。

3
00:00:02.859 --> 00:00:08.126
今回は、ユースメモとユースコールバックで、メモ化の使い分けを学びます。

4
00:00:08.126 --> 00:00:14.296
メモ化とは、一度作った結果を覚えておき、条件が変わらなければ再利用する考え方です。

5
00:00:14.296 --> 00:00:19.413
題材は、キーボードやマウスなどの商品を名前で絞り込む、商品検索です。

6
00:00:19.413 --> 00:00:25.131
計算結果を覚える場合と、関数の参照を覚える場合では、使うフックが変わります。

7
00:00:25.131 --> 00:00:29.345
どちらも最初からすべての部品へ付けるものではありません。

8
00:00:29.345 --> 00:00:34.612
タイプスクリプトの小さなコードで、違いを一つずつ確認していきましょう。

9
00:00:34.612 --> 00:00:36.916
まず、三つの機能を区別します。

10
00:00:36.916 --> 00:00:43.060
ユースメモは、依存する値が変わらない間、計算した値を再利用するためのフックです。

11
00:00:43.060 --> 00:00:51.970
ユースコールバックは、依存する値が変わらない間、関数の参照、つまり関数そのものの同一性を再利用するためのフックです。

12
00:00:51.970 --> 00:00:59.803
メモは、プロップスが変わらないときに、親の更新に伴う部品の再レンダーを省略できるようにする仕組みです。

13
00:00:59.803 --> 00:01:02.261
いずれも最適化のための機能です。

14
00:01:02.261 --> 00:01:08.713
もしメモ化を外したら動作が壊れるなら、それは最適化とは別の設計の問題かもしれません。

15
00:01:08.713 --> 00:01:13.628
画面の正しさを、キャッシュが残ることに頼らないようにしましょう。

16
00:01:13.628 --> 00:01:19.135
商品一覧の部品、プロダクトリスト・ティーエスエックスを作ります。

17
00:01:19.135 --> 00:01:26.707
親から受け取るプロップスは、商品の配列プロダクツと、選択を伝えるオンセレクトの二つです。

18
00:01:26.707 --> 00:01:34.451
部品全体をメモで包むことで、プロップスが変わらないときは再レンダーを省略できる形にします。

19
00:01:34.451 --> 00:01:40.303
商品がゼロ件なら、該当する商品がありません、という案内を表示します。

20
00:01:40.303 --> 00:01:45.466
一件以上あれば、商品名と価格と、選ぶためのボタンを並べます。

21
00:01:45.466 --> 00:01:48.907
なお、一覧のキーは商品のアイディーです。

22
00:01:48.907 --> 00:01:57.168
ここで大切なのは、一覧自身の作りではなく、親から渡される二つのプロップスが安定するかどうかです。

23
00:01:57.168 --> 00:02:02.696
メモの標準の比較では、各プロップスをオブジェクトイズで比べます。

24
00:02:02.696 --> 00:02:07.188
親がレンダーのたびに新しい配列や関数を作って渡すと、中身が同じように見えても、

25
00:02:07.188 --> 00:02:11.680
参照は別のものになります。

26
00:02:11.680 --> 00:02:16.690
その場合は、メモで包んでいても再レンダーは省略されません。

27
00:02:16.690 --> 00:02:23.427
逆に言えば、親の側で配列と関数の参照を安定させれば、メモが効く土台ができます。

28
00:02:23.427 --> 00:02:28.955
子の中のボタンで作る小さな関数は、親子の比較対象ではありません。

29
00:02:28.955 --> 00:02:34.484
この例で比べられるのは、プロダクツとオンセレクトの二つだけです。

30
00:02:34.484 --> 00:02:39.148
どこが比較対象なのかを絞ることが、メモ化の出発点です。

31
00:02:39.148 --> 00:02:45.740
親の部品、プロダクトサーチでは、検索語から表示する商品を計算します。

32
00:02:45.740 --> 00:02:54.466
入力されたクエリをトリムで前後の空白を取り除き、小文字にそろえたものをキーワードとします。

33
00:02:54.466 --> 00:02:58.537
ビジブルプロダクツはユースメモで作ります。

34
00:02:58.537 --> 00:03:06.293
中では、商品名を小文字にそろえ、キーワードを含むものだけをフィルターで残します。

35
00:03:06.293 --> 00:03:09.201
依存配列はキーワードだけです。

36
00:03:09.201 --> 00:03:16.957
キーワードが変われば計算し直し、同じなら前に作った配列をそのまま再利用できます。

37
00:03:16.957 --> 00:03:23.550
商品データは部品の外にある固定データなので、依存配列には入りません。

38
00:03:23.550 --> 00:03:29.948
もしエーピーアイから受け取る配列なら、その配列も依存値になります。

39
00:03:29.948 --> 00:03:35.319
次に、選択用の関数ハンドルセレクトを、ユースコールバックで作ります。

40
00:03:35.319 --> 00:03:41.480
商品が選ばれたら、そのアイディーをセレクトアイディーというステートへ入れます。

41
00:03:41.480 --> 00:03:47.325
この関数が使うのは、安定したステート更新関数だけなので、依存配列は空です。

42
00:03:47.325 --> 00:03:53.012
ユースコールバックに渡した関数は、フックを呼んだ時点では実行されません。

43
00:03:53.012 --> 00:03:59.488
あくまで、ボタンが押されたときに実行される関数を、参照を変えずに保持するだけです。

44
00:03:59.488 --> 00:04:06.755
もし変わるステートやプロップスの関数を読む処理を加えたら、その値を依存配列へ含めてください。

45
00:04:06.755 --> 00:04:12.600
古い値を読み続ける不具合を、最適化と引き換えに持ち込まないことが大切です。

46
00:04:12.600 --> 00:04:19.099
アプリ・ティーエスエックスでは、見出しとプロダクトサーチを配置するだけです。

47
00:04:19.099 --> 00:04:20.638
動作を確認します。

48
00:04:20.638 --> 00:04:24.742
初期状態は検索結果が三件で、選択中はなし、です。

49
00:04:24.742 --> 00:04:27.649
マウスと検索すると一件になります。

50
00:04:27.649 --> 00:04:32.951
マウスを選ぶボタンを押すと、選択中の表示がマウスに変わります。

51
00:04:32.951 --> 00:04:37.055
検索条件を変えても、選択中の商品は維持されます。

52
00:04:37.055 --> 00:04:40.646
存在しない商品名ではゼロ件の案内が出ます。

53
00:04:40.646 --> 00:04:46.461
そして、検索のヒントを開閉しても、検索結果や選択状態は変わりません。

54
00:04:46.461 --> 00:04:52.105
ヒントの開閉はキーワードを変えないため、ユースメモの配列の参照も維持され、

55
00:04:52.105 --> 00:04:57.748
メモ化した一覧の再レンダーを省略できる構造になっています。

56
00:04:57.748 --> 00:05:02.228
依存配列は、回数を抑えるための都合で決めるものではありません。

57
00:05:02.228 --> 00:05:06.997
計算や関数の中で読む値のうち、変わる可能性があるものが依存値です。

58
00:05:06.997 --> 00:05:12.054
ユースメモではキーワード、ユースコールバックでは今回は何もありません。

59
00:05:12.054 --> 00:05:16.101
ここで、なぜ商品配列が入らないのかをもう一度確認します。

60
00:05:16.101 --> 00:05:22.748
プロダクツは部品の外に置かれた固定データで、レンダーのたびに作り直されることがないからです。

61
00:05:22.748 --> 00:05:29.106
もし商品をステートやプロップスで管理するなら話は変わり、依存配列に含める必要があります。

62
00:05:29.106 --> 00:05:33.008
依存値を正しく書くことが、メモ化を安全に使う前提です。

63
00:05:33.008 --> 00:05:36.513
最適化を入れるかどうかは、先に計測して判断します。

64
00:05:36.513 --> 00:05:41.561
今回のように商品が数件なら、単純にフィルターするだけでも通常は十分です。

65
00:05:41.561 --> 00:05:47.310
この小さな例は、高速化が必要だと主張するものではなく、仕組みを学ぶためのものです。

66
00:05:47.310 --> 00:05:54.041
実際に遅さを感じたら、リアクト開発者ツールのプロファイラーなどで、対象のレンダーを調べましょう。

67
00:05:54.041 --> 00:05:57.126
比べるときは、同じデータ量と操作を使います。

68
00:05:57.126 --> 00:06:02.454
開発時のストリクトモードによる追加実行と、本番環境の動作は区別してください。

69
00:06:02.454 --> 00:06:09.605
ヒント開閉時に一覧のプロップスが維持されることだけでは、アプリ全体が速くなったとは結論づけられません。

70
00:06:09.605 --> 00:06:11.311
落とし穴を三つ挙げます。

71
00:06:11.311 --> 00:06:15.718
一つ目、レンダーのたびに新しい設定オブジェクトを作って依存配列に入れると、

72
00:06:15.718 --> 00:06:20.125
参照が毎回変わるため、毎回計算し直してしまいます。

73
00:06:20.125 --> 00:06:25.243
必要な文字列を直接依存値にするか、設定は計算の中で作る方法を検討します。

74
00:06:25.243 --> 00:06:32.351
二つ目、メモで包んでも、その部品自身のステートや、読み取っているコンテキストが変われば更新されます。

75
00:06:32.351 --> 00:06:37.611
手動の比較関数を書く場合は、関数のプロップスも含めて比べる必要があります。

76
00:06:37.611 --> 00:06:44.435
三つ目、リアクトコンパイラーが有効な環境では、自動的なメモ化で手動の指定が必要な場面が減ります。

77
00:06:44.435 --> 00:06:49.411
バージョンだけで判断せず、プロジェクトのビルド設定を確認してください。

78
00:06:49.411 --> 00:06:50.311
まとめです。

79
00:06:50.311 --> 00:06:56.235
計算した値を再利用したいときはユースメモ、関数の参照を再利用したいときはユースコールバック、

80
00:06:56.235 --> 00:07:02.159
そして子の再レンダーを省略したいときはメモ、と役割で使い分けます。

81
00:07:02.159 --> 00:07:08.758
三つは単独ではなく、親で参照を安定させ、子をメモで包むことで、初めて効果がつながります。

82
00:07:08.758 --> 00:07:12.657
今回、記事のコードそのままをタイプスクリプトの厳密な型チェックにかけて、

83
00:07:12.657 --> 00:07:16.556
エラーがないことを確認しました。

84
00:07:16.556 --> 00:07:21.055
絞り込みの計算もノード・ジェーエスで実行して確かめています。

85
00:07:21.055 --> 00:07:27.654
ブラウザー上での実際の描画や、再レンダーの回数の目視確認は、実行環境の制約で未実施です。

86
00:07:27.654 --> 00:07:32.753
次回は、ユーストランジションとユースディファードバリューを学びます。

87
00:07:32.753 --> 00:07:34.103
お疲れさまでした。
