VIDEO LESSON
Next.jsのuseContext入門:Providerでテーマと状態を共有するの解説動画
再生時間 7:39動画を別のタブで開く ↗
動画の字幕・文字起こしを読む
再生中の字幕を濃い黒で表示し、一番上に追従します。字幕の行を選ぶと、その位置から再生できます。
- 0:00こんにちは。
- 0:00今回は、ネクストジェイエスのユーズコンテキスト入門です。
- 0:05テーマ切り替えを例に、プロバイダーでテーマと状態を共有する方法を学びます。
- 0:10ユーズコンテキストは、祖先にあるプロバイダーから値を受け取るリアクトのフックです。
- 0:17テーマや表示設定のように、複数の部品が必要とする値を、中間の部品へ何段もプロップスで渡さずに共有できます。
- 0:25この動画では、ページズルーターとタイプスクリプトを使い、型付きプロバイダーと専用フックを作り、
- 0:30最後にアプリルーターでの配置の違いまで確認します。
- 0:36まず、なぜコンテキストが必要なのかです。
- 0:39親から孫、さらにその先へ同じ値を渡し続けると、中間の部品が自分では使わない値まで受け取って渡す、
- 0:44いわゆるバケツリレーが起きます。
- 0:50部品が増えるほど、受け渡しの経路が読みにくくなります。
- 0:54コンテキストを使うと、祖先のプロバイダーが用意した値を、必要な子孫が直接読み取れます。
- 1:01ただし大切な区別があります。
- 1:03ユーズコンテキストは値を届ける仕組みであり、状態そのものを自動で作る機能ではありません。
- 1:10状態の保持と更新には、ユーズステートなどを組み合わせます。
- 1:15近くの親子で完結する受け渡しなら、プロップスのほうが流れを追いやすい場合もあります。
- 1:22テーマを共有するコンテキストを実装します。
- 1:25ファイルは、エスアールシー配下のコンテキストフォルダーにある、テーマコンテキスト・ティーエスエックスです。
- 1:32画面に示した前半では、まずテーマの型をライトとダークの二択に限定し、共有する値の型として、
- 1:37現在のテーマと切り替え関数をまとめたテーマバリューを定義します。
- 1:43次にクリエイトコンテキストでコンテキストを作ります。
- 1:46ここへ渡す初期値は、対応するプロバイダーが祖先にない場合のフォールバックです。
- 1:52この例ではアンディファインドを使い、配置忘れを後で専用フックで検出できるようにします。
- 1:58コンテキストはモジュールのトップレベルで一度だけ定義し、描画のたびに作り直しません。
- 2:03続いてプロバイダー本体です。
- 2:05テーマプロバイダーは、ユーズステートでテーマを保持し、初期値はライトです。
- 2:10切り替え関数のトグルテーマは、現在の値を受け取り、ライトならダークへ、ダークならライトへ反転させます。
- 2:17関数形式で更新するため、古い値に依存しない安全な書き方になっています。
- 2:22用意したテーマと切り替え関数を、バリューとしてコンテキストプロバイダーへ渡し、
- 2:25子要素をその内側に置きます。
- 2:29トグルテーマが値を更新すると、そのコンテキストを読む子孫へ新しい値が伝わります。
- 2:34なおこの例ではブラウザーの保存領域を使わないため、ページを完全に再読み込みすると、
- 2:38初期値のライトへ戻ります。
- 2:42次に、ページズルーターの共通部分へプロバイダーを配置します。
- 2:46ファイルはアンダースコアエーピーピー・ティーエスエックスです。
- 2:50全ページを表すコンポーネントをテーマプロバイダーで囲むことで、どのページからでも同じテーマを読めるようになります。
- 2:58既存のアンダースコアエーピーピーがある場合は、グローバルシーエスエスやレイアウトなどの処理を残し、
- 3:03プロバイダーで必要な範囲だけを囲んでください。
- 3:08サンプルでファイル全体を上書きして、既存の設定を失わないようにすることが大切です。
- 3:13同じプロバイダーがマウントされたままのクライアント側のページ移動では状態を共有できますが、
- 3:17プロバイダーをページごとに作り直す場合や、ブラウザーを再読み込みする場合は、
- 3:22状態の寿命が変わります。
- 3:26読み取り側は、専用フックのユーズテーマを用意します。
- 3:30このフックは内部でユーズコンテキストを呼び、取得した値をチェックします。
- 3:34もし値がアンディファインドなら、プロバイダーの内側で使われていないということなので、
- 3:39エラーを投げて配置忘れをすぐ気付けるようにします。
- 3:43チェックを通過すれば、型がテーマバリューに確定した値を返します。
- 3:47利用側は、ユーズテーマを呼ぶだけで、テーマと切り替え関数を取り出せます。
- 3:52毎回コンテキストを直接読み、未定義かどうかを各部品で繰り返し判定する必要がなくなり、
- 3:56使い方も統一できます。
- 3:59この一手間が、大きなアプリでの事故防止につながります。
- 4:03子コンポーネントから読み取りと更新を行う例です。
- 4:06テーマボタンは、ユーズテーマから現在のテーマと切り替え関数を受け取ります。
- 4:12ボタンをクリックするとトグルテーマが呼ばれ、押下状態を示すエーリアプレストには、
- 4:15ダークかどうかを渡します。
- 4:19表示文字も、ダークなら有効、そうでなければ無効と切り替わります。
- 4:24ポイントは、このボタンへテーマをプロップスで渡す必要がないことです。
- 4:29親がテーマを知らなくても、ボタン自身がコンテキストから直接読むため、間に部品が増えても受け渡しを書き足す必要がありません。
- 4:38ページ側の例です。
- 4:39テーマページもユーズテーマでテーマを読み、背景色と文字色を、ダークかどうかで切り替えます。
- 4:45ページの中には先ほどのテーマボタンが置かれています。
- 4:49開発サーバーでスラッシュテーマへアクセスすると、ボタンとページが同じテーマを参照し、
- 4:54クリックで表示がまとめて切り替わることが確認できます。
- 4:59ボタンが状態を更新し、ページがその結果を描くという役割分担です。
- 5:04どちらもプロバイダーが持つ一つの状態を見ているため、値が食い違うことがありません。
- 5:10共有したい値と、それを使う場所が離れているほど、この仕組みの効果が分かりやすくなります。
- 5:16再描画と値の管理に注意します。
- 5:19プロバイダーの値が変わると、コンテキストを読むコンポーネントは更新を受け取ります。
- 5:26値の比較にはオブジェクトイズが使われます。
- 5:30この例のバリューは新しいオブジェクトとして渡されるため、プロバイダーが別の理由で再描画された場合にも参照が変わり、
- 5:36読む側が更新されることがあります。
- 5:42実際に不要な再描画が問題になったら、コンテキストの責務を分ける、プロバイダーの配置を狭める、
- 5:50必要に応じてユーズメモやユーズコールバックで値を安定させる、といった方法を検討します。
- 5:57ただしメモ化しても、テーマ自体が変わった際の利用側の更新は必要です。
- 6:03対策は、実測してから入れてください。
- 6:06アプリルーターでの利用です。
- 6:08プロバイダーのファイルはユーズクライアントで始め、クライアントコンポーネントとして用意し、
- 6:12必要な部分を囲みます。
- 6:16サーバーコンポーネントのレイアウトから、そのプロバイダーを読み込んで子要素を渡すことはできます。
- 6:23ただし、サーバーコンポーネント自身がユーズコンテキストでクライアントの状態を読む構成にはできません。
- 6:30境界を意識して、状態を持つ部分だけをクライアント側へ寄せるのが基本です。
- 6:35あわせてセキュリティの注意です。
- 6:38コンテキストはアクセス権限を保証する仕組みではありません。
- 6:42表示名などを共有する用途には使えますが、認証と認可はサーバー側でも確認し、
- 6:47秘密のエーピーアイキーをコンテキストへ入れてブラウザーへ渡すことは避けてください。
- 6:53最後に、コンテキストを広げすぎない設計です。
- 6:56まず、テーマや設定を必要とする部品を確認し、必要な範囲にプロバイダーを置きます。
- 7:03アプリ全体で本当に必要なのか、画面の一部で足りるのかを考えてください。
- 7:08次に、更新頻度の違う値を整理します。
- 7:11頻繁に変わる入力値と、ほとんど変わらない設定を同じコンテキストへまとめると、
- 7:16利用側の更新範囲が広がる場合があります。
- 7:20実際の描画を確認し、役割に応じて分割するか判断します。
- 7:25まとめです。
- 7:25クリエイトコンテキストで入れ物を作り、プロバイダーがユーズステートで状態を持ち、
- 7:30専用フックで安全に読む。
- 7:34この三点セットを押さえれば、テーマ共有を自分で実装できます。
この動画で学べること
Next.jsでuseContextを使い、テーマを共有する実践例を紹介。型付きProvider、専用Hook、更新と再描画、Pages RouterとApp Routerの配置の違いを解説します。
解説記事・サンプルコードを読む:Next.jsのuseContext入門:Providerでテーマと状態を共有する →