Day 5・状態の設計と再利用 — 大きくしても壊れない作り
状態をどこに置くか — 共通の親へ持ち上げる
2つの部品で同じ値を使いたいとき、状態を共通の親へ持ち上げ、単一の情報源にまとめる考え方をつかむ。
同じ値を2つの部品で使いたくなったとき
アプリが小さいうちは、状態(state)を使う部品の中に置いておけば十分でした。ところが画面が育つと、「同じ値を複数の部品で使いたい」場面が必ず出てきます。たとえば、入力欄に打った文字を、別の場所にあるプレビューにも映したい。このとき、それぞれの部品が自分だけのuseStateを持っていると、値がズレて食い違います。
解決の定石が「状態を持ち上げる(lifting state up)」です。共有したい値を、その値を使う部品たちの「共通の親」へ移動させ、親から子へpropsで配ります。値の置き場所を1か所に決める、という発想です。この1か所のことを「単一の情報源(source of truth、信頼できる唯一の出どころ)」と呼びます。
なぜ子ではなく親に置くのか
同じ値のコピーが2つあると、片方だけ更新されて食い違う事故が起きます。値の置き場所を1つに絞れば、食い違いようがありません。親を「その値の持ち主」と決め、子は親からもらって表示し、変えたいときは親に頼む。所有権を1つにするのが、大きくしても壊れないコツです。
// アンチパターン: 値の持ち主が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>;
}// 親が 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>;
}ポイントは、子の役割が変わることです。持ち上げる前は子が「自分の値」を持っていましたが、持ち上げた後は子は値を持ちません。親から value をもらって表示し、変えたいときは親からもらった onChange を呼んで「変えてほしい」と伝えるだけ。値を持たず、もらって使う部品を「制御された部品(controlled component)」と呼びます。
- どの部品がその値を必要とするかを洗い出す
- それら全部を含む「いちばん近い共通の親」を探す
- 状態(useState)をその親に置く
- 値は props で子へ配り、更新関数も props で渡して「変えてほしい」を親に伝える
持ち主が複数
同じ値のコピーがあちこちにあり、更新が伝わらず食い違う
// 各所で別々の useState("") を持つ
// 入力しても他の部品には反映されない持ち主は1つ
親が唯一の持ち主。子は props でもらうので、常に同じ値を見る
// 親: const [name, setName] = useState("")
// 子A: <Input value={name} onChange={setName} />
// 子B: <Preview name={name} />AIにはこう聞く
「入力欄とプレビューで同じ値を共有したいのに連動しない。状態を持ち上げるべき?どこに置けばいい?」と、共有したい値と使う場所を伝えると、共通の親の場所まで含めて提案してくれます。AIが出したコードで『値の持ち主が1つになっているか(コピーが増えていないか)』だけは自分で確認しましょう。
まとめると、共有したい値は「使う部品たちの共通の親」へ持ち上げ、置き場所を1つに絞る。これが単一の情報源です。この原則を守るだけで、状態の食い違いという定番のバグの多くを未然に防げます。
読んでも腑に落ちない所は、AIに噛み砕いてもらいましょう。
理解度チェック
答えられれば、面接で説明できる状態に一歩近づきます。
2つの子コンポーネントで同じ値を共有したい。Reactでの定石はどれ?
「単一の情報源(single source of truth)」の説明として最も適切なものはどれ?
状態を持ち上げると、子コンポーネントの役割はどう変わりますか。
記述式です。まず自分の言葉で答えを考えてから、模範解答を開いて自己採点してください。