🔖

ReactのLifting State Upについてまとめる

に公開

コンポーネント同士の連携

コンポーネント同士でデータを連携するにはどうしたらいいですか?という質問を後輩からもらいました。
実際に実装されているコードを示して説明をしたんですが、公式ドキュメントには"Sharing State Between Components"という章で触れられていました。
後輩くんたちは英語苦手なようなので簡単にまとめようと思います。

Lifting State up

"Stateの持ち上げ"と訳すんでしょうか。
2つのコンポーネントの状態を同時に変更したいときに、
同期したいコンポーネントそれぞれに状態を持っても渡すことができません。
そのため

  1. 子コンポーネントから状態を削除する。
  2. 最も近接した共通の親コンポーネントからデータを渡す
  3. 共通の親に状態を持たせ、

という手順で状態を親に持ち上げて、コンポーネント間でデータを共有することができます。

実際にやってみる

実例として公式ドキュメントにあるテキストボックスの同期をやってみましょう。

ベース
このインプットコンポーネントの2つのvalueを同期してみます。

export default function SyncedInputs() {
  return (
    <>
      <Input label="First input" />
      <Input label="Second input" />
    </>
  );
}

function Input({ label }) {
  const [text, setText] = useState('');

  function handleChange(e) {
    setText(e.target.value);
  }

  return (
    <label>
      {label}
      {' '}
      <input
        value={text}
        onChange={handleChange}
      />
    </label>
  );
}
  1. 子コンポーネントから状態を削除
function Input({ label }) {
  // Stateを削除
  // const [text, setText] = useState('');

  function handleChange(e) {
    setText(e.target.value);
  }

  return (
    <label>
      {label}
      {' '}
      <input
        value={text}
        onChange={handleChange}
      />
    </label>
  );
}
  1. 最も近接した親コンポーネントからデータを渡す
export default function SyncedInputs() {
  return (
    <>
      <Input label="First input" text="text"/>
      <Input label="Second input" text="text"/>
    </>
  );
}
  1. 共通の親に状態を持たせる
    状態を持たせ、ハンドラを渡すことで状態を変化させます。
export default function SyncedInputs() {
  //  ここで状態を持たせ、ハンドラを渡す
  const [text, setText] = useState("");

  function handleChange(e) {
      setText(e.target.value);
  }    
  
  return (
    <>
      <Input label="First input" text={ text } handleChange={handleChange}/>
      <Input label="Second input" text={ text } handleChange={handleChange}/>
    </>
  );
}

最終形

import { useState } from "react";

export default function SyncedInputs() {
  const [text, setText] = useState("");

  function handleChange(e) {
    setText(e.target.value);
  }
  return (
    <>
      <Input label="First input" text={text} handleChange={handleChange} />
      <Input label="Second input" text={text} handleChange={handleChange} />
    </>
  );
}

function Input({ label, handleChange, text }) {
  return (
    <label>
      {label} <input value={text} onChange={handleChange} />
    </label>
  );
}

これで2つのインプットコンポーネントの同期がとれるようになりました。

まとめ

上記の手順に沿って状態を押し上げることで、コンポーネント間でのデータを連携することができました。
データによってはストアで管理してあげるなどの必要があるものもあると思いますが、
このような手順で子コンポーネント間でのデータ連携が簡単に取れます。
React Doc Betaにはこんな感じで日頃使っていても言語化していないTipsなどもあって面白いです。

GitHubで編集を提案

Discussion