0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Stateのリフトアップについて

Last updated at Posted at 2022-05-24

ローカルStateの管理の仕方に迷いがでてきたので、しっかり調べてみる。

stateのリフトアップ

Reactの公式ドキュメントの例を考える。

基本的な設計

BoilingVerdict
const BoilingVerdict = (props) => {
  if (props.celsius >= 100) {
    return <p>The water would boil.</p>;
  }
  return <p>The water would not boil.</p>;
}
Calculator
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>
  );
}

stateのリフトアップ1.png

CalculatorコンポーネントはtemperatureというStateを持つ。
Calculatorコンポーネントのinputから入力があるとtemperatureは更新される。
celsiusというプロパティでparseFloat(temperature)がBoilingVerdictコンポーネントに渡され、表示される。

変化する値をもう一つ追加

基本的な設計にもう一つの変数を追加する。
input部分をTemperatureInputコンポーネントとして抽出。

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>
    );
 }
Calculator
  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>
    );
  }

stateのリフトアップ2.png

TemperatureInputコンポーネントはscaleによって2種類に分かれ、入力があるとtemperatureとscaleという2つのStateを更新する。
temperatureとscaleという2つのStateは親であるCalculatorコンポーネントに配置することで、それぞれのTemperatureInputコンポーネントは共通の値を更新することが可能になる。
複数のコンポーネントで共通の値を利用したい場合、直近の共通祖先コンポーネントにそのstateを配置してstateのリフトアップを行う。(トップダウン型のデータフローの力を借りている)

propsやstateから派生的に作りだす事のできるデータについては、stateに保持すべきではない

今回の例では、インプットされた値のみを保存している。(計算後の値は保存していない)
これによって、元のユーザー入力の精度を損なわずにもう片方の入力フィールドに適用したり、クリアしたりできる。

参考

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?