WEBVTT

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

2
00:00:00.892 --> 00:00:04.757
今回は、ネクストジェイエスのユーズステート実践です。

3
00:00:04.757 --> 00:00:09.959
カウンターと入力フォームを例に、状態の持ち方と更新の注意点を学びます。

4
00:00:09.959 --> 00:00:16.054
ユーズステートは、コンポーネントが画面の状態を記憶するためのリアクトのフックです。

5
00:00:16.054 --> 00:00:21.703
ボタンを押した回数やフォームの入力値など、操作に合わせて変わる値に使います。

6
00:00:21.703 --> 00:00:27.574
この動画では、タイプスクリプトとページズルーターを前提に、型推論、関数による更新、

7
00:00:27.574 --> 00:00:33.446
オブジェクトの更新を順に確認し、最後にアプリルーターでの境界まで説明します。

8
00:00:33.446 --> 00:00:38.277
記事はリアクト十八とネクストジェイエス十三のプロジェクトで使える例を前提にしていますが、

9
00:00:38.277 --> 00:00:43.108
考え方自体は現在のバージョンでも共通です。

10
00:00:43.108 --> 00:00:46.591
まず、なぜ普通の変数では足りないのかです。

11
00:00:46.591 --> 00:00:53.557
変数へ新しい値を代入しただけでは、リアクトは画面を描き直す必要があると分かりません。

12
00:00:53.557 --> 00:00:59.528
ユーズステートを使うと、現在の値と、更新するための関数がペアで返ります。

13
00:00:59.528 --> 00:01:04.669
更新関数を呼ぶことで、リアクトへ次の値と再描画を依頼できます。

14
00:01:04.669 --> 00:01:10.640
再描画のとき、コンポーネントは新しい状態を受け取って画面を作り直します。

15
00:01:10.640 --> 00:01:17.772
つまりユーズステートは、値を覚える場所と、画面更新の合図をまとめて提供する仕組みです。

16
00:01:17.772 --> 00:01:23.245
この関係を押さえると、以降の更新方法の違いが理解しやすくなります。

17
00:01:23.245 --> 00:01:31.040
ボタン操作や入力のように、利用者の行動で変わる値ほど、この仕組みの恩恵が分かりやすくなります。

18
00:01:31.040 --> 00:01:32.707
カウンターを作ります。

19
00:01:32.707 --> 00:01:40.283
ファイルは、エスアールシー配下のコンポーネンツフォルダーにある、カウンター・ティーエスエックスです。

20
00:01:40.283 --> 00:01:46.798
ユーズステートに初期値を渡すと、現在のカウントと、更新関数のセットカウントが返ります。

21
00:01:46.798 --> 00:01:55.132
この例では初期値が数値なので、状態の型はナンバーと推論され、毎回ユーズステートに型を明示する必要はありません。

22
00:01:55.132 --> 00:01:59.678
初期値はプロップスのイニシャルカウントで、省略時はゼロです。

23
00:01:59.678 --> 00:02:02.405
表示側はカウントをそのまま読みます。

24
00:02:02.405 --> 00:02:07.860
状態を作る行と、表示する行を分けて読むと、値の流れが追いやすくなります。

25
00:02:07.860 --> 00:02:12.639
前の値から次の値を計算するときは、更新関数を渡すのが安全です。

26
00:02:12.639 --> 00:02:17.881
画面のアドスリーは、現在の値を受け取って一を足す関数を三回渡します。

27
00:02:17.881 --> 00:02:22.506
リアクトは保留中の更新を順に適用するため、結果は三増えます。

28
00:02:22.506 --> 00:02:27.824
対して、セットカウントにカウント足す一を三回渡す書き方は、同じ描画時点のカウントから計算した同じ値を三回渡すことになり、

29
00:02:27.824 --> 00:02:33.143
一しか増えません。

30
00:02:33.143 --> 00:02:41.160
連続更新や、直前の値に依存する処理では、古い値を直接読まず、現在の値を受け取る関数形式を選んでください。

31
00:02:41.160 --> 00:02:44.397
これが状態更新で最もつまずきやすい点です。

32
00:02:44.397 --> 00:02:50.872
更新がキューに積まれて順に処理されるイメージを持つと、この差を間違えにくくなります。

33
00:02:50.872 --> 00:02:56.724
ページ側ではカウンターを読み込み、イニシャルカウントに十を渡して表示します。

34
00:02:56.724 --> 00:03:01.884
開発サーバーでスラッシュカウンターを開くと、最初に十が表示され、一増やすで十一、

35
00:03:01.884 --> 00:03:07.043
三増やすで十四、リセットで十へ戻る流れを確認できます。

36
00:03:07.043 --> 00:03:12.587
ここで大切なのは、イニシャルカウントは状態を作る最初の値だという点です。

37
00:03:12.587 --> 00:03:19.363
親からの値が後で変わっても、ユーズステートがそのたびに状態を作り直すわけではありません。

38
00:03:19.363 --> 00:03:26.140
親が値を管理すべき場合は、状態を親へ移し、値と更新用コールバックを渡す設計も検討します。

39
00:03:26.140 --> 00:03:30.452
リセットは、クリック時点の初期値へ明示的に戻す操作です。

40
00:03:30.452 --> 00:03:31.779
次にフォームです。

41
00:03:31.779 --> 00:03:39.150
プロフィールエディターでは、表示名と、お知らせ希望の真偽値を、一つのオブジェクト状態として持ちます。

42
00:03:39.150 --> 00:03:45.195
型はプロフィールで、ユーズステートに型引数で示し、初期値は空の名前とフォルスです。

43
00:03:45.195 --> 00:03:51.240
入力欄は、バリューにプロフィールの名前を渡し、変更イベントで入力値を受け取ります。

44
00:03:51.240 --> 00:03:55.294
更新では、現在のオブジェクトを展開してコピーし、名前だけを新しい値へ差し替えた、

45
00:03:55.294 --> 00:03:59.348
新しいオブジェクトを渡します。

46
00:03:59.348 --> 00:04:04.214
入力欄の値が状態と結び付くため、打つたびに下の表示名も連動します。

47
00:04:04.214 --> 00:04:06.278
制御された入力の基本形です。

48
00:04:06.278 --> 00:04:13.944
名前とお知らせ希望を別々の状態に分ける方法もありますが、まとめて扱うと提出時の処理が一か所に集まります。

49
00:04:13.944 --> 00:04:16.345
チェックボックス側も同じ考え方です。

50
00:04:16.345 --> 00:04:21.080
チェック状態をプロフィールのお知らせ希望と結び付け、変更時はチェックの真偽を受け取り、

51
00:04:21.080 --> 00:04:25.815
現在のオブジェクトをコピーしてその項目だけ差し替えます。

52
00:04:25.815 --> 00:04:29.416
注意点は、元のオブジェクトを直接書き換えないことです。

53
00:04:29.416 --> 00:04:34.884
ユーズステートの更新は、クラス部品のようにオブジェクトの一部を自動で結合しません。

54
00:04:34.884 --> 00:04:39.953
残したい項目はスプレッドでコピーし、新しいオブジェクトとして渡してください。

55
00:04:39.953 --> 00:04:45.155
入れ子になったオブジェクトでは、変更する階層まで新しい値を作る必要があります。

56
00:04:45.155 --> 00:04:49.156
表示名が空なら未入力と出す分岐も、状態を読むだけの処理です。

57
00:04:49.156 --> 00:04:51.710
実行タイミングと型の注意点です。

58
00:04:51.710 --> 00:04:58.256
更新関数を呼んでも、実行中のイベント処理の中では、状態変数はすぐには変わりません。

59
00:04:58.256 --> 00:05:01.129
新しい値を受け取るのは次の描画です。

60
00:05:01.129 --> 00:05:06.238
途中で古い値を読んで処理を続けると、想定とずれることがあります。

61
00:05:06.238 --> 00:05:14.220
また、フックはコンポーネントやカスタムフックのトップレベルで呼び、条件分岐やループの中へ置きません。

62
00:05:14.220 --> 00:05:18.211
呼び出し順序が毎回同じであることが前提だからです。

63
00:05:18.211 --> 00:05:23.639
型については、初期値だけでは意図が伝わらない場合に型引数を使います。

64
00:05:23.639 --> 00:05:30.344
たとえば文字列またはヌルを許す状態は、ユーズステートにその型を示してヌルで始めます。

65
00:05:30.344 --> 00:05:33.826
開発時のストリクトモードにも注意します。

66
00:05:33.826 --> 00:05:40.441
ストリクトモードでは、初期化関数や更新関数が追加で実行されることがあります。

67
00:05:40.441 --> 00:05:46.534
そのため、これらの関数の中では、値を計算する処理だけを行ってください。

68
00:05:46.534 --> 00:05:52.017
通信、ログ送信、外部の配列やオブジェクトの変更といった副作用を入れると、

69
00:05:52.017 --> 00:05:57.501
追加実行によって二重に起きたり、結果がぶれたりします。

70
00:05:57.501 --> 00:06:03.246
前の値を受け取って次の値を返す、純粋な計算として書くのが原則です。

71
00:06:03.246 --> 00:06:10.905
問題が起きたときに、入力が同じなら出力も同じになる形だと、原因を切り分けやすくなります。

72
00:06:10.905 --> 00:06:16.476
本番だけの問題と決めつけず、開発時の挙動も前提に設計しましょう。

73
00:06:16.476 --> 00:06:18.628
アプリルーターで使う場合です。

74
00:06:18.628 --> 00:06:24.654
状態やイベントを扱うコンポーネントは、クライアントコンポーネントの境界内へ置きます。

75
00:06:24.654 --> 00:06:30.249
たとえばカウンターの先頭で、インポートより前にユーズクライアントを指定します。

76
00:06:30.249 --> 00:06:37.135
すべての親ページをクライアント化する必要はなく、状態を持つ部品だけを境界内に寄せるのが基本です。

77
00:06:37.135 --> 00:06:43.304
もう一つ、クライアントコンポーネントも初回表示用にサーバーで描画されることがあります。

78
00:06:43.304 --> 00:06:50.334
描画時にブラウザーの情報へ無条件に触れる実装は避け、必要な同期はユーズエフェクトへ分けてください。

79
00:06:50.334 --> 00:06:54.208
サーバーで値が存在しない前提を忘れないことが大切です。

80
00:06:54.208 --> 00:06:56.382
最後に確認のしかたです。

81
00:06:56.382 --> 00:07:03.630
一回のクリックだけでなく、連続更新や、リセットした後の再操作まで試してください。

82
00:07:03.630 --> 00:07:11.603
前の状態から次を計算する場合は、関数型の更新で同じ描画内の更新を正しく扱えるかを見ます。

83
00:07:11.603 --> 00:07:20.844
また、プロップスを初期値に使っても、その後のプロップス変更が自動で状態へ反映されるわけではありません。

84
00:07:20.844 --> 00:07:25.012
親で値を管理するのか、入力途中の値を子に保持するのかを先に決めることが、

85
00:07:25.012 --> 00:07:29.179
設計の分かれ目です。

86
00:07:29.179 --> 00:07:30.266
まとめです。

87
00:07:30.266 --> 00:07:38.783
値を覚えるのはユーズステート、前の値からの計算は関数形式、オブジェクトは新しい値を作って更新。

88
00:07:38.783 --> 00:07:44.581
この三点を押さえれば、カウンターもフォームも安全に実装できます。

89
00:07:44.581 --> 00:07:52.916
迷ったら、値がどこで生まれ、誰が更新し、誰が読むのかを書き出してから実装すると整理できます。
