ステートを利用することにより、データ(状態)の保持、更新が出来るようになりました。
また、Reactアプリケーションは複数のコンポーネントから構成される事を知りました。
さらに、コンポーネントからコンポーネントへプロパティを経由して値の受け渡しが行えるようになりました。
それでは、ステートはどこで持つべきでしょうか?
独立性を考えると個々のコンポーネントでステートを持つ事が良いような気もしますが、親コンポーネントで一元管理するのが定番のようです。
今回は親コンポーネントでステートを管理してみましょう。
目次
ステートの使い方と概要
その前に、ステートの使い方の概要を説明します。今回は親コンポーネント(Appコンポーネント)にステートを持たせます。ステート値の表示、ステート値の更新は、親コンポーネントの各子コンポーネントで行います。その為には、親コンポーネントから各子コンポーネントへステート値とステート更新関数をプロパティ経由で渡す事によって、ステート値の表示と更新を行います。
これを頭の隅に入れておきながら以降を実装してみます。
やりたい事
コーヒーの種類とサイズを選択すると選択した内容を画面へ表示させます。
ルールとしては、以下の通りです。
・コーヒーの種類は “普通” と “プレミアム” の2種類
・普通のコーヒーは “レギュラーサイズ” と “ラージサイズ” が選べる
・プレミアムコーヒーはサイズが選べない
![](https://dennie.tokyo/it/wp-content/uploads/2022/08/スクリーンショット-2022-08-08-18.17.04.png)
用意するコンポーネント
以下のコンポーネントを用意します。
・Appコンポーネント
ステートを持ち、各コンポーネントの親となるコンポーネント。
・MenueSelect コンポーネント
コーヒーの種類(普通、プレミアム)が選択できるラジオボタンを持つコンポーネント。
・CoffeeJudgment コンポーネント
選択されたコーヒーの種類によってサイズ選択を表示させるかどうかを判断するコンポーネント。普通コーヒーの場合、サイズを選択できるようにし、プレミアムコーヒーの場合はサイズを選択できないようにする。
・SizeSelect コンポーネント
コーヒーのサイズ(レギュラー、ラージ)が選択できるラジオボタンを持つコンポーネント。
・Result コンポーネント
選択された内容を表示するコンポーネント。
コンポーネントの説明
Appコンポーネント
親となるAppコンポーネントは2つのステートを保持します。一つ目は、選択されたコーヒーの種類を保持するステート。二つ目は、選択されたコーヒーのサイズを保持するステートになります。
Appコンポーネントは、子コンポーネントへステート値、ステート更新関数をプロパティ経由で渡します。
一つ目のステート(値と更新関数)は、MenueSelectコンポーネントへ。二つ目のステートはCoffeeJudgmentコンポーネントへ渡します。一つ目と二つ目のステート値をResultコンポーネントへ渡し選択した内容を表示します。
import React from 'react';
import MenueSelect from './MenueSelect';
import CoffeeJudgment from './CoffeeJudgment';
import Result from './Result';
function App() {
// 選択されたコーヒーの種類を保持するステート
const [menueVal, setMenueVal] = React.useState("normal");
// 選択されたコーヒーのサイズを保持するステート
const [sizeVal, setSizeVal] = React.useState("regular");
// 子コンポーネントを呼び出す
return (
<>
<MenueSelect val={menueVal} setVal={setMenueVal} />
<CoffeeJudgment val={sizeVal} setVal={setSizeVal} coffeeKind={menueVal} />
<Result menueVal={menueVal} sizeVal={sizeVal} />
</>
);
}
export default App;
MenueSelectコンポーネント
普通、プレミアムの2種類のどちらかを選べるラジオボタンを表示します。
function MenueSelect({val, setVal}) {
// ラジオボタンのイベントハンドラ
const selectVal = e => setVal(e.target.value);
// ブラウザ表示処理
return (
<>
<p>コーヒーの種類を選んでください。</p>
<div>
<input type="radio" value="normal" onChange={selectVal} checked={val === 'normal'}/>普通
</div>
<div>
<input type="radio" value="premium" onChange={selectVal} checked={val === 'premium'}/>プレミアム
</div>
</>
);
}
export default MenueSelect;
CoffeeJudgment コンポーネント
普通のコーヒーが選択されている場合、レギュラーサイズかラージサイズかを選択できるSizeSelect コンポーネントを表示します。プレミアムコーヒーの場合、サイズが選択できない事を表示します。
import SizeSelect from './SizeSelect';
function CoffeeJudgment({val, setVal, coffeeKind}) {
const judgment = ()=>{
// 普通コーヒの場合、レギュラーサイズかラージサイズかを選択できる SizeSelect コンポーネントを返却する。
if (coffeeKind === 'normal') {
return <SizeSelect val={val} setVal={setVal}/>
// プレミアムコーヒーの場合、サイズが選択できない事を返却する。
} else {
return <p>プレミアムコーヒーはワンサイズとなります。</p>
}
}
// ブラウザ表示処理
return (
<>{judgment()}</>
);
}
export default CoffeeJudgment;
SizeSelect コンポーネント
レギュラーサイズ、ラージサイズかを選べるラジオボタンを表示します。
function SizeSelect({val, setVal}) {
// ラジオボタンのイベントハンドラ
const selectVal = e => setVal(e.target.value);
// ブラウザ表示処理
return (
<>
<p>サイズを選んでください。</p>
<div>
<input type="radio" value="regular" onChange={selectVal} checked={val === 'regular'}/>レギュラー
</div>
<div>
<input type="radio" value="large" onChange={selectVal} checked={val === 'large'}/>ラージ
</div>
</>
);
}
export default SizeSelect;
Result コンポーネント
コーヒーの種類、コーヒーのサイズを受け取り、受け取った内容を表示するコンポーネントになります。コーヒーのサイズの表示は、コヒーの種類が普通(normal)の場合、受け取ったサイズを表示します。コーヒーの種類が普通以外(プレミアム)の場合、ハイフン(-) を表示します。
function Result({menueVal, sizeVal}) {
const judgment = ()=>{
if (menueVal === 'normal') {
return sizeVal
} else {
return "-"
}
}
// ブラウザ表示処理
return (
<>
<p>選択内容は以下の通りです。</p>
<div>コーヒーの種類:{menueVal}</div>
<div>コーヒーのサイズ:{judgment()}</div>
</>
);
}
export default Result;
最後に
このように親コンポーネントでステートを持ち、親コンポーネントから子コンポーネントへステートをプロパティ経由で渡し、子コンポーネントにてステートの表示、更新を行います。