- DAY 32:フォームとState 前半 ― 「入力が画面に届くまで」の流れを理解する
- 入力の流れを「一本の線」としてイメージする
- 名前入力フォームを作る準備をする
- ユーザー入力 → onChange の流れを作る
- onChange → State更新 のつながりを作る
- State更新 → 画面に反映(inputのvalue)までつなげる
- 名前入力フォームの完成テンプレート(DAY 32 前半版)
- DAY 32 前半のまとめ ― 「入力→State→画面」の一本線を持つ
- DAY 32:フォームとState 中盤 ― 「入力→State→画面」を設計目線で深掘りする
- 入力の4ステップをもう一度「設計図」として整理する
- onChangeの中で「何をするか」を設計する
- State更新が「画面全体の挙動」を決める
- 「入力→State→画面」の流れを少しだけ複雑にしてみる
- 名前入力フォームの「中盤版テンプレート」
- DAY 32 中盤のまとめ ― 流れを「設計の道具」として使う
- DAY 32:フォームとState(後半)― 「入力→State→画面」を自分の型として定着させる
- 入力の4ステップを「自分のフォームの基本パターン」にする
- 名前入力フォームを「ちゃんとしたフォーム」に近づける
- 「入力→State→画面」の流れを、別の視点からもう一度見る
- 名前入力フォームの「後半版テンプレート」
- DAY 32 後半のまとめ ― 流れを「いつでも使える自分の型」にする
DAY 32:フォームとState 前半 ― 「入力が画面に届くまで」の流れを理解する
DAY 32の前半では、 フォームとStateの関係を 1本の流れとしてイメージできるようになること を目標にします。
テーマはとてもシンプルです。
ユーザー入力 ↓ onChange ↓ State更新 ↓ 画面に反映
この流れを、実際の 名前入力フォーム を題材にして、 ステップバイステップで追いかけていきます。
入力の流れを「一本の線」としてイメージする
まずは全体像を言葉でつかむ
Reactのフォームでは、 ユーザーが文字を入力してから画面に反映されるまでに、次のような流れが起きています。
- ユーザー入力
- キーボードで文字を打つ
- ブラウザが「入力された」というイベントを発生させる
- onChange
onChangeに渡した関数が呼ばれる- イベントオブジェクト
eから、入力された値を取り出す
- State更新
setState(例えばsetName)を呼び出して、Stateを新しい値に更新する
- 画面に反映
- Reactが再レンダリングを行う
value={state}によって、入力欄の表示が新しいStateに置き換わる
この流れが、 「フォームとStateの基本サイクル」 です。
DAY 32前半では、このサイクルを 実際のコードと一緒に、丁寧に追いかけていきます。
名前入力フォームを作る準備をする
Stateを用意するところから始める
まず、名前を保存するためのStateを用意します。
import { useState } from "react";
function NameForm() {
const [name, setName] = useState("");
return (
<div>
<h2>DAY 32:フォームとState(前半)</h2>
{/* ここにフォームを作っていきます */}
</div>
);
}
export default NameForm;
JSXここでのポイントは、
nameが「現在の名前」を表すStateであることsetNameが「名前を更新するための関数」であること
です。
この name を、 入力欄と画面表示の両方に使っていきます。
ユーザー入力 → onChange の流れを作る
inputタグにonChangeをつける
次に、名前を入力するための input を置き、 onChange を設定します。
function NameForm() {
const [name, setName] = useState("");
const handleChange = (e) => {
console.log("onChangeが呼ばれました");
console.log("入力された値:", e.target.value);
};
return (
<div>
<h2>DAY 32:フォームとState(前半)</h2>
<input
type="text"
onChange={handleChange}
placeholder="名前を入力してください"
/>
</div>
);
}
JSXここで起きていることをステップで説明します。
- ユーザーが入力欄に文字を打つ
- ブラウザが「入力された」というイベントを発生させる
onChange={handleChange}によって、handleChangeが呼ばれるe.target.valueに「今入力された文字列」が入っている
この段階では、まだStateは更新していません。 「入力された値を受け取るところ」までができた状態です。
onChange → State更新 のつながりを作る
入力された値をStateに保存する
次に、handleChange の中で setName を呼び出し、 Stateを更新するようにします。
function NameForm() {
const [name, setName] = useState("");
const handleChange = (e) => {
const inputValue = e.target.value;
setName(inputValue);
};
return (
<div>
<h2>DAY 32:フォームとState(前半)</h2>
<input
type="text"
onChange={handleChange}
placeholder="名前を入力してください"
/>
<p>現在の名前(State):{name}</p>
</div>
);
}
JSXここでの流れはこうです。
- ユーザーが文字を入力する
handleChangeが呼ばれるinputValue = e.target.valueで入力された文字列を取り出すsetName(inputValue)でStatenameを更新する- Reactが再レンダリングし、
{name}の表示が新しい値になる
この時点で、
ユーザー入力 ↓ onChange ↓ State更新 ↓ 画面に反映(
<p>の表示)
という流れが完成しています。
State更新 → 画面に反映(inputのvalue)までつなげる
Controlled Componentにして「入力欄もStateで支配する」
次のステップは、 入力欄の中身もStateで管理することです。
function NameForm() {
const [name, setName] = useState("");
const handleChange = (e) => {
const inputValue = e.target.value;
setName(inputValue);
};
return (
<div>
<h2>DAY 32:フォームとState(前半)</h2>
<input
type="text"
value={name}
onChange={handleChange}
placeholder="名前を入力してください"
/>
<p>現在の名前(State):{name}</p>
</div>
);
}
JSXここでのポイントは、
value={name}によって、入力欄の表示内容がStatenameに完全に紐づいていることonChangeで入力のたびにStateを更新していること
これにより、 入力欄は Controlled Component(制御されたコンポーネント) になります。
流れをもう一度まとめる
この名前入力フォームでは、 次のような流れが起きています。
- ユーザー入力
- キーボードで文字を打つ
- onChange
handleChangeが呼ばれるe.target.valueから入力値を取り出す
- State更新
setName(inputValue)でStatenameを更新する
- 画面に反映
- Reactが再レンダリングする
value={name}によって入力欄の表示が新しいnameになる<p>現在の名前(State):{name}</p>の表示も更新される
この一連の流れが、 「フォームとStateの基本サイクル」 です。
名前入力フォームの完成テンプレート(DAY 32 前半版)
DAY 32前半の内容をすべて含んだ、 名前入力フォームの完成コードをまとめます。
import { useState } from "react";
function NameForm() {
const [name, setName] = useState("");
const handleChange = (e) => {
const inputValue = e.target.value;
setName(inputValue);
};
return (
<div>
<h2>DAY 32:フォームとState(前半)― 名前入力フォーム</h2>
<input
type="text"
value={name}
onChange={handleChange}
placeholder="名前を入力してください"
/>
<p>現在の名前(State):{name}</p>
</div>
);
}
export default NameForm;
JSXこのコンポーネントは、
- ユーザー入力
- onChange
- State更新
- 画面に反映
という流れを、 最もシンプルな形で体現しています。
DAY 32 前半のまとめ ― 「入力→State→画面」の一本線を持つ
DAY 32前半で、自分の中にしっかり残してほしいのは次のポイントです。
- フォームとStateの関係は、 ユーザー入力 → onChange → State更新 → 画面に反映 という一本の流れで考えられること。
- onChangeでは、 イベントオブジェクト
eからe.target.valueを取り出し、 それをsetStateに渡すのが基本であること。 - Stateを画面に反映するには、
value={state}や{state}のように、 JSXの中でStateを使うことが必要であること。 - 名前入力フォームのような小さな例でも、 この流れを意識して書くことで、 「フォームとStateのつながり」がはっきり見えてくること。
この一本の流れが体に馴染むと、 この先のフォーム設計(複数項目・バリデーション・送信処理など)も、 すべてこのサイクルの延長として自然に理解できるようになっていきます。
DAY 32:フォームとState 中盤 ― 「入力→State→画面」を設計目線で深掘りする
DAY 32の中盤では、前半で触れた
ユーザー入力 ↓ onChange ↓ State更新 ↓ 画面に反映
という流れを、設計目線でより深く理解することを目標にします。
題材は引き続き「名前入力フォーム」ですが、 単に動かすだけでなく、
- どこで何が起きているのか
- どこをどう変えると挙動が変わるのか
- どうすれば「きれいなフォーム設計」になるのか
を意識しながら見ていきます。
入力の4ステップをもう一度「設計図」として整理する
4つのステップをコードと対応させる
まず、前半で作った基本的な名前入力フォームを振り返ります。
import { useState } from "react";
function NameForm() {
const [name, setName] = useState("");
const handleChange = (e) => {
const inputValue = e.target.value;
setName(inputValue);
};
return (
<div>
<h2>DAY 32:フォームとState(中盤)― 名前入力フォーム</h2>
<input
type="text"
value={name}
onChange={handleChange}
placeholder="名前を入力してください"
/>
<p>現在の名前(State):{name}</p>
</div>
);
}
export default NameForm;
JSXこのコードの中に、 「ユーザー入力 → onChange → State更新 → 画面に反映」の4ステップがすべて入っています。
それぞれを対応させると、こうなります。
- ユーザー入力jsx
<input type="text" ... />- ユーザーがキーボードで文字を打つ場所です。
- onChangejsx
onChange={handleChange}- 入力が変化した瞬間に呼ばれる関数を指定しています。
- State更新jsx
const handleChange = (e) => { const inputValue = e.target.value; setName(inputValue); };e.target.valueから入力値を取り出し、setNameでStateを更新しています。
- 画面に反映jsx
value={name} ... <p>現在の名前(State):{name}</p>value={name}によって入力欄の表示がStateに紐づき、<p>の{name}によって画面にもStateが表示されています。
中盤では、この4ステップを「ただの流れ」ではなく、 「フォーム設計の基本パターン」として意識してみてください。
onChangeの中で「何をするか」を設計する
単にStateを更新するだけが仕事ではない
前半では、handleChange の中で
const inputValue = e.target.value;
setName(inputValue);
JSXと書きましたが、 中盤では「ここに何を挟めるか」を考えてみます。
例えば、次のようなことができます。
- 前後の空白を削除する
- 最大文字数を制限する
- 特定の文字を禁止する
実際に、前後の空白を削除する例を見てみます。
const handleChange = (e) => {
const inputValue = e.target.value;
const trimmed = inputValue.trim();
setName(trimmed);
};
JSXこの変更によって、
- ユーザーが「 山田 」と入力しても、Stateには「山田」だけが保存されます。
- 画面に表示される名前も「山田」になります。
ポイント:
onChangeは「入力された値を受け取る場所」であり、 同時に「入力値を整形・チェックする場所」でもあります。
この感覚があると、 フォームの挙動を「設計する」ことができるようになります。
State更新が「画面全体の挙動」を決める
名前に応じてメッセージを変える
Stateが更新されると、 画面のどこにでもそのStateを使うことができます。
例えば、名前が入力されているかどうかでメッセージを変えてみます。
function NameForm() {
const [name, setName] = useState("");
const handleChange = (e) => {
const inputValue = e.target.value;
setName(inputValue);
};
const isEmpty = name.trim() === "";
return (
<div>
<h2>DAY 32:フォームとState(中盤)― 名前入力フォーム</h2>
<input
type="text"
value={name}
onChange={handleChange}
placeholder="名前を入力してください"
/>
<p>現在の名前(State):{name}</p>
{isEmpty ? (
<p style={{ color: "gray" }}>まだ名前が入力されていません。</p>
) : (
<p style={{ color: "green" }}>こんにちは、{name}さん!</p>
)}
</div>
);
}
JSXここで起きていることは、
nameが空かどうかをisEmptyで判定しているisEmptyに応じて表示するメッセージを切り替えている
という流れです。
重要な感覚:
Stateは「入力欄の中身」だけでなく、 画面全体の挙動(メッセージ・色・ボタンの有効/無効など)を決める材料になる。
これが、 「フォームとState」が単なる入力欄の話ではなく、 UI全体の設計の話になっていくポイントです。
「入力→State→画面」の流れを少しだけ複雑にしてみる
名前の長さに応じて注意メッセージを出す
中盤では、 流れ自体は同じまま、少しだけロジックを足してみます。
例えば、「名前が20文字を超えたら注意メッセージを出す」 という仕様を追加してみます。
import { useState } from "react";
function NameFormWithLengthWarning() {
const [name, setName] = useState("");
const handleChange = (e) => {
const inputValue = e.target.value;
setName(inputValue);
};
const length = name.length;
const isTooLong = length > 20;
return (
<div>
<h2>DAY 32:フォームとState(中盤)― 名前入力+長さチェック</h2>
<input
type="text"
value={name}
onChange={handleChange}
placeholder="名前を入力してください(最大20文字推奨)"
/>
<p>現在の名前:{name}</p>
<p>文字数:{length}</p>
{isTooLong && (
<p style={{ color: "red" }}>
名前が長すぎます。20文字以内に収めることをおすすめします。
</p>
)}
</div>
);
}
export default NameFormWithLengthWarning;
JSXここでも、
- ユーザー入力
- onChange
- State更新
- 画面に反映
という流れは変わっていません。
ただし、 Stateを使って「追加のロジック」を画面に反映している点が中盤のポイントです。
名前入力フォームの「中盤版テンプレート」
DAY 32中盤の内容をまとめた、 少しだけ賢くなった名前入力フォームのテンプレートを示します。
import { useState } from "react";
function NameFormMid() {
const [name, setName] = useState("");
const handleChange = (e) => {
const inputValue = e.target.value;
// 前後の空白を削除してからStateに保存
const trimmed = inputValue.trim();
setName(trimmed);
};
const isEmpty = name === "";
const length = name.length;
const isTooLong = length > 20;
return (
<div>
<h2>DAY 32:フォームとState(中盤)― 名前入力フォーム(設計版)</h2>
<input
type="text"
value={name}
onChange={handleChange}
placeholder="名前を入力してください"
/>
<p>現在の名前(State):{name}</p>
<p>文字数:{length}</p>
{isEmpty && (
<p style={{ color: "gray" }}>名前がまだ入力されていません。</p>
)}
{!isEmpty && !isTooLong && (
<p style={{ color: "green" }}>こんにちは、{name}さん!</p>
)}
{isTooLong && (
<p style={{ color: "red" }}>
名前が少し長いようです。20文字以内にすると読みやすくなります。
</p>
)}
</div>
);
}
export default NameFormMid;
JSXこのテンプレートでは、
- onChangeで入力値を整形してからStateに保存している
- Stateを使って「空かどうか」「長すぎないか」を判定している
- 判定結果に応じてメッセージを切り替えている
という形で、 「入力→State→画面」の流れを設計目線で使いこなしています。
DAY 32 中盤のまとめ ― 流れを「設計の道具」として使う
DAY 32中盤で、自分の中に定着させてほしいのは次のポイントです。
- フォームとStateの流れは、 ユーザー入力 → onChange → State更新 → 画面に反映 という一本の線であり、 そのどこにロジックを挟むかが「設計」のポイントになること。
- onChangeの中では、 単に
setState(e.target.value)するだけでなく、 入力値の整形・制限・チェックなどを行うことができること。 - Stateは、 入力欄の中身だけでなく、 メッセージ・色・ボタンの挙動など、画面全体の振る舞いを決める材料になること。
- 名前入力フォームのような小さな例でも、 「入力値に応じて画面の挙動を変える」という設計を意識すると、 フォームとStateの関係がぐっと立体的に見えてくること。
この設計目線が身につくと、 この先のフォーム設計(複数項目・バリデーション・送信処理・エラー表示など)も、 すべて「入力→State→画面」の流れの上に自然に乗せて考えられるようになっていきます。
DAY 32:フォームとState(後半)― 「入力→State→画面」を自分の型として定着させる
DAY 32の後半では、 これまで扱ってきた
ユーザー入力 ↓ onChange ↓ State更新 ↓ 画面に反映
という流れを、「いつでも使える自分の型」として定着させることを目標にします。
題材は引き続き「名前入力フォーム」ですが、 後半では少しだけ完成度を上げて、 「実際のアプリでもそのまま使えるフォーム」に近づけていきます。
入力の4ステップを「自分のフォームの基本パターン」にする
もう一度、流れをコードとセットで確認する
まず、名前入力フォームの基本形を再掲します。
import { useState } from "react";
function NameForm() {
const [name, setName] = useState("");
const handleChange = (e) => {
const inputValue = e.target.value;
setName(inputValue);
};
return (
<div>
<h2>DAY 32:フォームとState(後半)― 名前入力フォーム</h2>
<input
type="text"
value={name}
onChange={handleChange}
placeholder="名前を入力してください"
/>
<p>現在の名前(State):{name}</p>
</div>
);
}
export default NameForm;
JSXこの中に、4ステップがすべて入っています。
- ユーザー入力:
<input type="text" ... /> - onChange:
onChange={handleChange} - State更新:
setName(inputValue) - 画面に反映:
value={name}と{name}
後半では、この形を「覚える」のではなく、 「自分のフォームは必ずこの流れで考える」というレベルまで持っていきます。
名前入力フォームを「ちゃんとしたフォーム」に近づける
送信ボタンと簡単なバリデーションを追加する
実際のアプリでは、 入力して終わりではなく「送信する」という流れが入ります。
そこで、名前入力フォームに送信ボタンと簡単なチェックを追加してみます。
import { useState } from "react";
function NameFormFinal() {
const [name, setName] = useState("");
const handleChange = (e) => {
const inputValue = e.target.value;
// 前後の空白を削除してからStateに保存します。
const trimmed = inputValue.trim();
setName(trimmed);
};
const handleSubmit = (e) => {
e.preventDefault(); // ページのリロードを防ぎます。
if (name === "") {
alert("名前が入力されていません。");
return;
}
alert(`送信された名前:${name}`);
setName("");
};
const isEmpty = name === "";
return (
<div>
<h2>DAY 32:フォームとState(後半)― 名前入力フォーム(送信付き)</h2>
<form onSubmit={handleSubmit}>
<input
type="text"
value={name}
onChange={handleChange}
placeholder="名前を入力してください"
/>
<button type="submit" disabled={isEmpty}>
送信
</button>
</form>
<p>現在の名前(State):{name}</p>
{isEmpty ? (
<p style={{ color: "gray" }}>まだ名前が入力されていません。</p>
) : (
<p style={{ color: "green" }}>こんにちは、{name}さん!</p>
)}
</div>
);
}
export default NameFormFinal;
JSXここで起きていることを、流れに沿って整理します。
- ユーザー入力
- ユーザーが入力欄に文字を打ちます。
- onChange
handleChangeが呼ばれ、e.target.valueから入力値を取り出します。trim()で前後の空白を削除してからsetNameでStateを更新します。
- State更新
nameが新しい値に変わります。- Reactが再レンダリングし、
value={name}と{name}の表示が更新されます。
- 画面に反映
- 入力欄の中身が新しい
nameになります。 - 「現在の名前」やメッセージの表示も更新されます。
isEmptyの値も変わり、ボタンのdisabledやメッセージの内容が変わります。
- 入力欄の中身が新しい
- 送信処理
- ユーザーが「送信」ボタンを押すと、
handleSubmitが呼ばれます。 nameが空ならアラートで警告し、空でなければ送信された名前を表示します。- 送信後に
setName("")でStateをリセットし、フォームを初期状態に戻します。
- ユーザーが「送信」ボタンを押すと、
ここまで来ると、「フォームとState」が実際のアプリの動きにかなり近づいています。
「入力→State→画面」の流れを、別の視点からもう一度見る
Controlled Componentとしての完成形
この名前入力フォームは、 典型的な Controlled Component になっています。
value={name}→ 入力欄の表示は常にStatenameによって決まります。onChange={handleChange}→ 入力のたびにStateが更新されます。handleSubmitでStateから値を取り出して処理します。
この形は、 ログインフォーム・プロフィール編集・問い合わせフォームなど、 ほぼすべてのフォームでそのまま使える「基本パターン」です。
重要なポイント:
「ユーザー入力 → onChange → State更新 → 画面に反映 →(必要なら送信)」 という流れを、Controlled Componentとして1セットで考える。
これが、Reactでフォームを扱うときの「標準の考え方」になります。
名前入力フォームの「後半版テンプレート」
DAY 32後半の内容をまとめた、 再利用しやすいテンプレートとしての名前入力フォームを示します。
import { useState } from "react";
function NameFormTemplate() {
const [name, setName] = useState("");
// 入力された値をStateに反映する(整形もここで行う)
const handleChange = (e) => {
const inputValue = e.target.value;
const trimmed = inputValue.trim();
setName(trimmed);
};
// フォーム送信時の処理
const handleSubmit = (e) => {
e.preventDefault();
if (name === "") {
alert("名前を入力してください。");
return;
}
alert(`送信された名前:${name}`);
setName("");
};
const isEmpty = name === "";
return (
<div>
<h2>DAY 32:フォームとState(後半)― 名前入力フォームテンプレート</h2>
<form onSubmit={handleSubmit}>
<div>
<label>
名前:
<input
type="text"
value={name}
onChange={handleChange}
placeholder="名前を入力してください"
/>
</label>
</div>
<div style={{ marginTop: "8px" }}>
<button type="submit" disabled={isEmpty}>
送信
</button>
</div>
</form>
<hr />
<div>
<p>現在の名前(State):{name}</p>
{isEmpty ? (
<p style={{ color: "gray" }}>まだ名前が入力されていません。</p>
) : (
<p style={{ color: "green" }}>こんにちは、{name}さん!</p>
)}
</div>
</div>
);
}
export default NameFormTemplate;
JSXこのテンプレートは、
useStateでフォームの値を管理するvalue+onChangeでControlled ComponentにするonSubmitでStateから値を取り出して処理する- 必要に応じてボタンの有効/無効やメッセージを切り替える
という、 「フォームとState」の基本セットをすべて含んでいます。
DAY 32 後半のまとめ ― 流れを「いつでも使える自分の型」にする
DAY 32後半で、自分の中にしっかり残してほしいのは次のポイントです。
- フォームとStateの流れは、 ユーザー入力 → onChange → State更新 → 画面に反映 →(送信) という一本の線であり、Reactフォームの基本サイクルであること。
- 名前入力フォームのような小さな例でも、
value+onChange+useState+onSubmitのセットを使うことで、 実際のアプリに近い「ちゃんとしたフォーム」になること。 - Controlled Componentとしてフォームを設計すると、 入力値の整形・チェック・エラー表示・ボタン制御・送信処理などを、 すべてReactの中で一貫して扱えるようになること。
- この名前入力フォームテンプレートを、 自分の中で「フォームの出発点」として持っておくと、 どんなフォームでも迷わず書き始められるようになること。
この「入力→State→画面」の型が体に馴染むと、 この先のフォーム・コンポーネント設計(複数項目・バリデーション・エラー管理・API連携など)が、 すべてこの型の応用として自然に組み立てられるようになっていきます。
