R初めてのReact

Day 5状態の設計と再利用 — 大きくしても壊れない作り

状態をどこに置くか — 共通の親へ持ち上げる

2つの部品で同じ値を使いたいとき、状態を共通の親へ持ち上げ、単一の情報源にまとめる考え方をつかむ。

同じ値を2つの部品で使いたくなったとき

アプリが小さいうちは、状態(state)を使う部品の中に置いておけば十分でした。ところが画面が育つと、「同じ値を複数の部品で使いたい」場面が必ず出てきます。たとえば、入力欄に打った文字を、別の場所にあるプレビューにも映したい。このとき、それぞれの部品が自分だけのuseStateを持っていると、値がズレて食い違います。

解決の定石が「状態を持ち上げる(lifting state up)」です。共有したい値を、その値を使う部品たちの「共通の親」へ移動させ、親から子へpropsで配ります。値の置き場所を1か所に決める、という発想です。この1か所のことを「単一の情報源(source of truth、信頼できる唯一の出どころ)」と呼びます。

なぜ子ではなく親に置くのか

同じ値のコピーが2つあると、片方だけ更新されて食い違う事故が起きます。値の置き場所を1つに絞れば、食い違いようがありません。親を「その値の持ち主」と決め、子は親からもらって表示し、変えたいときは親に頼む。所有権を1つにするのが、大きくしても壊れないコツです。

TSX
// アンチパターン: 値の持ち主が2人いる
function NameInput() {
  const [name, setName] = useState("");
  return <input value={name} onChange={(e) => setName(e.target.value)} />;
}

function Preview() {
  const [name] = useState(""); // 別のname。入力と連動しない
  return <p>こんにちは、{name}さん</p>;
}
持ち上げる前。入力とプレビューが別々に状態を持ち、食い違う恐れがある
TSX
// 親が name の唯一の持ち主(single source of truth)
function Form() {
  const [name, setName] = useState("");
  return (
    <div>
      <NameInput value={name} onChange={setName} />
      <Preview name={name} />
    </div>
  );
}

// 子は状態を持たず、もらって使う
function NameInput({ value, onChange }: { value: string; onChange: (v: string) => void }) {
  return <input value={value} onChange={(e) => onChange(e.target.value)} />;
}

function Preview({ name }: { name: string }) {
  return <p>こんにちは、{name}さん</p>;
}
持ち上げた後。親が唯一の持ち主になり、子はpropsで受け取る

ポイントは、子の役割が変わることです。持ち上げる前は子が「自分の値」を持っていましたが、持ち上げた後は子は値を持ちません。親から value をもらって表示し、変えたいときは親からもらった onChange を呼んで「変えてほしい」と伝えるだけ。値を持たず、もらって使う部品を「制御された部品(controlled component)」と呼びます。

  1. どの部品がその値を必要とするかを洗い出す
  2. それら全部を含む「いちばん近い共通の親」を探す
  3. 状態(useState)をその親に置く
  4. 値は props で子へ配り、更新関数も props で渡して「変えてほしい」を親に伝える

持ち主が複数

同じ値のコピーがあちこちにあり、更新が伝わらず食い違う

TSX
// 各所で別々の useState("") を持つ
// 入力しても他の部品には反映されない

持ち主は1つ

親が唯一の持ち主。子は props でもらうので、常に同じ値を見る

TSX
// 親: const [name, setName] = useState("")
// 子A: <Input value={name} onChange={setName} />
// 子B: <Preview name={name} />

AIにはこう聞く

「入力欄とプレビューで同じ値を共有したいのに連動しない。状態を持ち上げるべき?どこに置けばいい?」と、共有したい値と使う場所を伝えると、共通の親の場所まで含めて提案してくれます。AIが出したコードで『値の持ち主が1つになっているか(コピーが増えていないか)』だけは自分で確認しましょう。

まとめると、共有したい値は「使う部品たちの共通の親」へ持ち上げ、置き場所を1つに絞る。これが単一の情報源です。この原則を守るだけで、状態の食い違いという定番のバグの多くを未然に防げます。

読んでも腑に落ちない所は、AIに噛み砕いてもらいましょう。

理解度チェック

答えられれば、面接で説明できる状態に一歩近づきます。

Q1

2つの子コンポーネントで同じ値を共有したい。Reactでの定石はどれ?

Q2

「単一の情報源(single source of truth)」の説明として最も適切なものはどれ?

Q3

状態を持ち上げると、子コンポーネントの役割はどう変わりますか。

記述式です。まず自分の言葉で答えを考えてから、模範解答を開いて自己採点してください。