今回はReactのHookを2つ組み合わせてプログラムを組んでみます。親・子・孫の3つのコンポーネントを作り親と孫で同じ状態をキープするプログラムです。具体的には親と孫でそれぞれにボタン(加算・減算・リセット)を作りカウント数を共有してみます。
Contents
作成するプログラムの出力イメージ
親のボタン、孫のボタンどちらを押しても、親と孫に表示されているカウント数(現在値)が同時に変化します。
useContext設定ファイル
まず「src/contexts」ディレクトリにAppContext.jsファイルを作ります。useContextを使うための基本的な記述をします。createContextをインポートし、contextをAppContextという変数に入れます。それを他で利用できるようにエクスポートしています。
0 1 2 3 4 5 |
import {createContext} from 'react' const AppContext = createContext() export default AppContext |
App.js(親)コンポーネント
次に親を作成します。デフォルトで用意されているApp.jsに下記のプラグラムを記述します。
AppContextとuseRecucerそしてBモジュールをインポートします。
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
import './App.css'; import AppContext from './contexts/AppContext'; import B from './components/B'; import { useReducer } from 'react' const initialState = 0 const reducer = (prev, action) => { switch (action) { case 'plus': return prev + 1 case 'minus': return prev - 1 case 'reset': return 0 default: return prev } } function App() { const [count, dispatch] = useReducer(reducer, initialState) return ( <div className="App"> <h3>A</h3> <p>カウント数: {count}</p> <AppContext.Provider value={{ countContext: count, dispatchContext: dispatch }} > <button onClick={() => dispatch('plus')}>プラス</button> <button onClick={() => dispatch('minus')}>マイナス</button> <B /> </AppContext.Provider> </div> ); } export default App; |
useReducerの初期値を0、そしてreducerの処理を作ります。
function App() {}の中にuseReducerの式を記載します。
重要なのは
<AppContext.Provider value={{ countContext: count, dispatchContext: dispatch }} ></AppContext.Provider>
で囲まれた中でuseContextが使えるということです。この中に<B />が記載されているので、Bに含まれるCモジュール(孫)でもuseContextが使えるということになります。
useContext , useRecucerの詳しい説明は下記のリンクを参考にして下さい。
B(子)モジュール
BコンポーネントはCコンポーネントを読み込んでいるだけです。
表示したときにABCの区別が付きやすいように<hr>区切り線を入れています。
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
import C from './C'; import React from 'react' const B = () => { return ( <div> <hr></hr> <h3>B</h3> <hr></hr> <C /> </div> ) } export default B |
C(孫)モジュール
まず、useContext , AppContextをインポートしておきます。この2つは記述方法が違うので注意が必要です。
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
import React from 'react' import {useContext} from 'react' import AppContext from '../contexts/AppContext' const C = () => { const{countContext ,dispatchContext} = useContext(AppContext) return ( <div> <h3>C(孫)</h3> <button onClick ={()=>dispatchContext('plus')}>プラス</button> <button onClick ={()=>dispatchContext('plus')}>マイナス</button> <button onClick ={()=>dispatchContext('reset')}>リセット</button> 現在値 : {countContext} </div> ) } export default C |
親コンポーネント内でuseContextで使う変数を2つ定義しました。
<AppContext.Provider value={{ countContext: count, dispatchContext: dispatch }} >
- countContext: count
- dispatchContext: dispatch
この一行でuseContextの値をCモジュールモジュールで使えるようにしています。const{countContext ,dispatchContext} = useContext(AppContext)
あとはボタンや表示にこれらの変数を使えば良いだけです。
「ボタン」
<button onClick ={()=>dispatchContext(‘plus’)}>プラス</button>
「カウンター数の表示」
現在値 : {countContext}
親・子・孫で同時に値を変更
これまでは親(APP)と孫(C)だけでステートを共有していましたが、今度は子(B)でも共有できるようにします。APP・B・Cそれぞれにボタンを設置し、カウント数をそれぞれで共有してみます。
上記のプログラムができていればとても簡単。コピペで動かせるレベルです。変更するのはBだけでOKです。
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
import C from './C'; import {useContext} from 'react' import AppContext from '../contexts/AppContext' import React from 'react' const B = () => { const{countContext ,dispatchContext} = useContext(AppContext) return ( <div> <hr></hr> <h3>B(子)</h3> <button onClick ={()=>dispatchContext('plus')}>プラス</button> <button onClick ={()=>dispatchContext('plus')}>マイナス</button> <button onClick ={()=>dispatchContext('reset')}>リセット</button> 現在値 : {countContext} <hr></hr> <C /> </div> ) } export default B |
これで3つのコンポーネントで値を共有できるようになりました。
useRecucerとuseContextを使うとバケツリレーが無くなるのでとても良いですね。jQuery時代に作ったプログラムはバケツリレーだらけで途中で嫌になりました。useRecucerとuseContextの組み合わせ技はReactHooksの凄さを体感できる良い例ですね。