17.0.1コンテクストは、親コンポーネントのデータを子やさらにその下のコンポーネントから参照できるようにする仕組みです。useContextフックが、コンポーネントツリー内の関数コンポーネントからコンテクストを使えるようにします。前回は、クラスコンポーネントをuseStateフックで関数に書き替えました。今回はさらに、useContextフックを加えてみることがお題です。コンテクストをつくってuseContextフックで参照するまず、親のコンポーネントでコンテクストをつくらなければなりません。その関数がReact.createContext()です。引数は、コンテクストとして子に参照を許すデータの初期値です。複数ある場合には、オブジェクトで渡してください。コンテクストをつくると、Context.Providerコンポーネントが使えるようになります。このコンポーネントでJSXテンプレートを包めば、ラップされた子孫からコンテクストが参照できるようになる仕組みです。このとき、valueプロパティで子どもたちに渡すデータを定めます。React.createContext()メソッドに渡した初期値はあくまでデフォルトで、実際に参照されるのはvalueプロパティの値です。初期値が用いられるのは、Context.Providerコンポーネントにラップされていないコンポーネントが、コンテクストにアクセスしようとしたときくらいでしょう。React.createContext()メソッドが返したコンテクストは、他のモジュール(子コンポーネント)から参照する場合はexportしておかなければなりません。value={{プロパティ}}></コンテクスト.Provider>);}親コンポーネントのモジュールsrc/components/App.jsは、つぎのようにコンテクスト(GameContext)をつくってプロバイダ(GameContext.Provider)でラップします。初期値はわかりやすいように変数(initialContext)に定めました。コンテクストに加えたデータ(squaresとonClick)はプロパティを介さずに参照できますので、JSXの子コンポーネント(Board)から除いてしまって構いません。/></div></GameContext.Provider>);}データは、子コンポーネントがコンテクストから参照できるようになりました。モジュールsrc/components/Board.jsでuseContextフックを用いるよう書き替えたのが、つぎのコードです。コンテクスト(GameContext)からプロパティ(squares)を取り出しますので、関数コンポーネントの引数(props)は除いてしまいます。クリックイベントのハンドラ(onClick)は、もはやバケツリレーはしません。孫コンポーネント(Square)はハンドラに渡す引数(i)が要りますので、新たにプロパティ(id)として加えました。props.onClick(i)}/>;};孫コンポーネントのモジュールsrc/components/Square.jsは、クリックイベントのハンドラ(onClick)はコンテクストから取り出し、プロパティで受け取った引数(props.id)を渡して呼び出します。子から孫への中継をさらに減らす子のコンポーネントのモジュールsrc/components/Board.jsから孫コンポーネントには、前掲コードで新たに加えたプロパティのほか、もうひとつ(value)渡されていました。この参照は孫コンポーネントがコンテクストから取り出せます。すると、子コンポーネントはコンテクストを見る必要がありません。value={squares[i]}/>;};孫のモジュールsrc/components/Square.jsはコンテクストから必要なデータ(squares)を参照し、関数コンポーネントの引数オブジェクトから分割代入で受け取ったプロパティ(id)により取り出します。*/}{squares[id]}</button>);};子の盤面のコンポーネント(Board)はプロパティ(id)をひとつ孫に渡しているだけで、コンテクストには触れなくなりました。プロパティも受け取らず、表示に専念することになりました。孫のコンポーネント(Square)が必要なデータを、直にコンテクストから取り出して使えるようになったからです。ふたつのモジュールの記述全体を、つぎのコード001にまとめます。ゲーム情報の表示をコンポーネントに切り出すバケツリレーを気にすることもなくなりましたので、切り出せるコンポーネントはどんどん分けましょう。ルートコンポーネントのモジュールsrc/components/App.jsで、つぎの差し手あるいは勝者の情報(status)を表示するJSX要素(<div>)がそれです。className="game-info"><div>{status}</div></div></div></GameContext.Provider>);}準備として、ルートコンポーネントのモジュールsrc/components/App.jsの状態に勝者(winner)の変数を加えます。つぎの差し手(xIsNext)とともにあとでコンテクストに含めますので、初期値(initialContext)も与えておきましょう。*/}ゲーム情報を表示するために切り出した子モジュールsrc/components/GameInfo.jsは、コンテクストから必要なデータ(winnerとxIsNext)が受け取れます。それらの値にもとづいて、コンポーネントに表示すべき情報(status)を決めればよいのです(コード002)。GameInfo;改めて、ゲーム情報表示の子コンポーネント(GameInfo)を差し込むルートモジュールsrc/components/App.jsのコードです。Providerコンポーネントのvalueに必要な変数(xIsNextとwinner)を加えます。/></div></GameContext.Provider>);}これで、ルートコンポーネントのデータが、コンテクストによりコンポーネントツリーの中で共有することができました。モジュールsrc/components/App.jsの全体の記述は、つぎのコード003のとおりです。各モジュールの記述とアプリケーションの動きは、CodeSandboxに公開した以下のサンプル001でお確かめください。入門」シリーズに組み込むかたちで大幅に改訂。