ローカルStateの管理の仕方に迷いがでてきたので、しっかり調べてみる。
stateのリフトアップ
Reactの公式ドキュメントの例を考える。
基本的な設計
const BoilingVerdict = (props) => {
if (props.celsius >= 100) {
return <p>The water would boil.</p>;
}
return <p>The water would not boil.</p>;
}
const Calculator = (props) => {
// state
const [temperature, setTemperature] = useState({temperature: ''});
// 入力による処理
const handleChange = (e) => {
setTemperature({temperature: e.target.value});
}
return(
<fieldset>
<legend>Enter temperature in Celsius:</legend>
<input
value={temperature}
onChange={handleChange}
/>
<BoilingVerdict
celsius={parseFloat(temperature)} />
</fieldset>
);
}
CalculatorコンポーネントはtemperatureというStateを持つ。
Calculatorコンポーネントのinputから入力があるとtemperatureは更新される。
celsiusというプロパティでparseFloat(temperature)がBoilingVerdictコンポーネントに渡され、表示される。
変化する値をもう一つ追加
基本的な設計にもう一つの変数を追加する。
input部分をTemperatureInputコンポーネントとして抽出。
const TemperatureInput = (props) => {
const temperature = props.temperature;
const handleChange = (e) => props.onTemperatureChange(() => e.target.value);
const scale = props.scale;
return (
<fieldset>
<legend>Enter temperature in {scaleNames[scale]}:</legend>
<input value={temperature} onChange={handleChange} />
</fieldset>
);
}
const Calculator = () => {
const [temperature, setTemperature] = useState("");
const [scale, setScale] = useState("c");
const handleCelsiusChange = (temperature) => {
setTemperature(temperature);
setScale("c");
};
const handleFahrenheitChange = (temperature) => {
setTemperature(temperature);
setScale("f");
};
const celsius = scale === "f" ? tryConvert(temperature, toCelsius) : temperature;
const fahrenheit = scale === "c" ? tryConvert(temperature, toFahrenheit) : temperature;
return (
<div>
<TemperatureInput
scale="c"
temperature={celsius}
onTemperatureChange={handleCelsiusChange}
/>
<TemperatureInput
scale="f"
temperature={fahrenheit}
onTemperatureChange={handleFahrenheitChange}
/>
<BoilingVerdict celsius={parseFloat(temperature)} />
</div>
);
}
TemperatureInputコンポーネントはscaleによって2種類に分かれ、入力があるとtemperatureとscaleという2つのStateを更新する。
temperatureとscaleという2つのStateは親であるCalculatorコンポーネントに配置することで、それぞれのTemperatureInputコンポーネントは共通の値を更新することが可能になる。
複数のコンポーネントで共通の値を利用したい場合、直近の共通祖先コンポーネントにそのstateを配置してstateのリフトアップを行う。(トップダウン型のデータフローの力を借りている)
propsやstateから派生的に作りだす事のできるデータについては、stateに保持すべきではない
今回の例では、インプットされた値のみを保存している。(計算後の値は保存していない)
これによって、元のユーザー入力の精度を損なわずにもう片方の入力フィールドに適用したり、クリアしたりできる。
参考