概要
Reactアプリの作成を始めて最初に躓いた コンポーネント間でデータのやり取りをする基本 を自分なりに整理した。
背景と目的
前回、
Reactアプリの開発環境を整え、アプリを作り始めたが最初に強く感じたこととして
コンポーネント間でデータのやり取りをすることが、初学者にとって非常にハードルが高く感じる
がある。今までよくjQueryやベタのDOMを使って何もハードルを感じることなかったので、それとは対照的だ。そこで、ひとまずこのハードルを自分の中で乗り越えねばならないと思い、簡単なサンプルでもいいのでとにかくちゃんと動くものを整理してメモしておく。
詳細
1. やることを整理
ドロップダウンボックスの選択値を、divタグのinnerTextに表示する
といった非常に単純なこと。ここで、ドロップダウンボックスとdivタグは親子関係を想定しない。私が今知りたいのは、親子関係にない単純なコンポーネント同士である。、すなわち
// ドロップダウンボックスの関数コンポーネント function MyDropDown() { return ( <select></select> ); } // divの関数コンポーネント function MyDiv() { return ( <div></div> ); }
よくWeb上にあるサンプルは、以下のような親子関係にあるものばかり出てくるのだが、これではない。
function MyDropDown() { return ( <select></select> <div></div> ); }
2. App.js
いきなりだが、作成したものは以下。
import { useState, createRef } from 'react'; import { createContext, useContext } from 'react'; import './App.css'; const MyValue = createContext(1); const MyRef = createRef(); function MyDropDown() { const { myValue, setMyValue } = useContext(MyValue); function handleChange() { setMyValue(MyRef.current.value); } return ( <select onChange={handleChange} ref={MyRef} defaultValue={myValue}> <option value="1">1</option> <option value="2">2</option> <option value="3">3</option> </select> ); } function MyDiv() { const { myValue, setMyValue } = useContext(MyValue); return ( <div>{myValue}</div> ); } function App() { const [myValue, setMyValue] = useState(1); const value = { myValue, setMyValue }; return ( <div className="App"> <MyValue.Provider value={value}> <MyDropDown></MyDropDown> <MyDiv></MyDiv> </MyValue.Provider> </div> ); } export default App;
いくつかポイントを整理する。
2.1 Context
Reactにおいてコンポーネント間でデータを共有する仕組みとしてContextというものがある。これをApp.jsのグローバルで宣言しておく。
const MyValue = createContext(1);
このデータを使うには、コンポーネント内でuseContextを使って
const { myValue, setMyValue } = useContext(MyValue);
とする。
2.2 Ref
Refはコンポーネントの参照、すなわち今までidを振って参照したりしていたことに対応するReactでの仕組み。これもApp.jsのグローバルで宣言しておく。
const MyRef = createRef();
この参照を用いれば、ドロップダウンボックスの現在の選択値は、
MyRef.current.value
で参照できる。
2.3 Contextへの引き渡し
初めて見たときかなり戸惑ったが、とにかくstate機能を使って作成した変数をContextに紐づけるということ。 まず、以下のようにuseStateを使って状態管理用の変数myValueと値をセットする関数setMyValueを用意。
const [myValue, setMyValue] = useState(1); const value = { myValue, setMyValue };
そして、Context.Providerで共有したいコンポーネントを囲う。valueプロパティに、作成したmyValue、setMyValueを渡す。
<MyValue.Provider value={value}> <MyDropDown></MyDropDown> <MyDiv></MyDiv> </MyValue.Provider>
2.4 ドロップダウンボックス
現在のドロップダウンボックスの値が変化したら、MyRef.current.valueをMyValueに保存。
function MyDropDown() { const { myValue, setMyValue } = useContext(MyValue); function handleChange() { setMyValue(MyRef.current.value); } return ( <select onChange={handleChange} ref={MyRef} defaultValue={myValue}> <option value="1">1</option> <option value="2">2</option> <option value="3">3</option> </select> ); }
2.5 div
Contextから値をもらってinnerTextに与える。
function MyDiv() { const { myValue, setMyValue } = useContext(MyValue); return ( <div>{myValue}</div> ); }
3. 動作確認
動作確認するまでもないが、ドロップダウンボックスを操作するとdivのテキストがちゃんと変化する。

4. Contextをまとめて使いやすくする(2025/03/21追記)
App.jsの例では、1つのファイル内で使用しているが、実際には複数のファイルにまたがってグローバルデータとして共有することが多い。そのため、その場合でも使いやすいように、Contextの作成と呼び出しを1つのファイルにまとめて使いやすくする方法がある。
以下では、MyValueContext.tsxにContextの作成と呼び出しをまとめ、App.tsxで使用する例を記載する。この方法であれば、MyDropDownやMyDivのようなコンポーネントがそれぞれ別のファイルにあったとしても、MyValueContextというモジュールを読み込むことでグローバルデータMyValueにアクセスできる。
3.1 MyValueContext.tsx
- トップレベルでContextを作成
- ContextProviderというコンポーネントを用意
- その中で、Stateを用意
- MyValueContext.Providerを最外殻としてそのStateをvalueに渡す
- MyValueContext.Providerの中身には、他のReactNode children が受け取れるようにしておく
- MyValueのuseContextを返すuseMyValueContextをあらかじめ定義しておく
import { createContext, useContext, useState } from "react"; export const MyValue = createContext(1); export const MyValueContextProvider: React.FC<{children: React.ReactNode}> = ({ children }) => { const [myValue, setMyValue] = useState(1); return ( <MyValueContext.Provider value={[myValue, setMyValue]}> {children} </MyValueContext.Provider> ); } export const useMyValueContext = () => useContext(MyValue);
3.2 App.tsx
- MyValueContextをインポート
- createContext, useContext, useStateを削除
- useContextをuseMyValueContextに置き換え
- MyValue.ProviderをMyValueContextProviderに置き換えてMyDropDownとMyDivを囲む
- value引数は不要となる
import { createRef } from 'react'; import { MyValueContextProvider, useMyValueContext } from 'MyValueContext'; import './App.css'; const MyRef = createRef(); function MyDropDown() { const { myValue, setMyValue } = useMyValuContext(); : 以下略 } function MyDiv() { const { myValue, setMyValue } = useMyValuContext(); : 以下略 } function App() { return ( <div className="App"> <MyValueContextProvider> <MyDropDown></MyDropDown> <MyDiv></MyDiv> </MyValueContextProvider> </div> ); } export default App;
まとめと今後の課題
Reactアプリをやり始めて最初に感じたハードルを自分の中でクリアできてよかった。