モダンJavaScriptの基礎から始める挫折しないためのReact入門 60日コース | フォーム・コンポーネント設計 - DAY 32:フォームとState

React 60日で身につけるReact
スポンサーリンク
スポンサーリンク
  1. DAY 32:フォームとState 前半 ― 「入力が画面に届くまで」の流れを理解する
  2. 入力の流れを「一本の線」としてイメージする
    1. まずは全体像を言葉でつかむ
  3. 名前入力フォームを作る準備をする
    1. Stateを用意するところから始める
  4. ユーザー入力 → onChange の流れを作る
    1. inputタグにonChangeをつける
  5. onChange → State更新 のつながりを作る
    1. 入力された値をStateに保存する
  6. State更新 → 画面に反映(inputのvalue)までつなげる
    1. Controlled Componentにして「入力欄もStateで支配する」
    2. 流れをもう一度まとめる
  7. 名前入力フォームの完成テンプレート(DAY 32 前半版)
  8. DAY 32 前半のまとめ ― 「入力→State→画面」の一本線を持つ
  9. DAY 32:フォームとState 中盤 ― 「入力→State→画面」を設計目線で深掘りする
  10. 入力の4ステップをもう一度「設計図」として整理する
    1. 4つのステップをコードと対応させる
  11. onChangeの中で「何をするか」を設計する
    1. 単にStateを更新するだけが仕事ではない
  12. State更新が「画面全体の挙動」を決める
    1. 名前に応じてメッセージを変える
  13. 「入力→State→画面」の流れを少しだけ複雑にしてみる
    1. 名前の長さに応じて注意メッセージを出す
  14. 名前入力フォームの「中盤版テンプレート」
  15. DAY 32 中盤のまとめ ― 流れを「設計の道具」として使う
  16. DAY 32:フォームとState(後半)― 「入力→State→画面」を自分の型として定着させる
  17. 入力の4ステップを「自分のフォームの基本パターン」にする
    1. もう一度、流れをコードとセットで確認する
  18. 名前入力フォームを「ちゃんとしたフォーム」に近づける
    1. 送信ボタンと簡単なバリデーションを追加する
  19. 「入力→State→画面」の流れを、別の視点からもう一度見る
    1. Controlled Componentとしての完成形
  20. 名前入力フォームの「後半版テンプレート」
  21. DAY 32 後半のまとめ ― 流れを「いつでも使える自分の型」にする

DAY 32:フォームとState 前半 ― 「入力が画面に届くまで」の流れを理解する

DAY 32の前半では、 フォームとStateの関係を 1本の流れとしてイメージできるようになること を目標にします。

テーマはとてもシンプルです。

ユーザー入力 ↓ onChange ↓ State更新 ↓ 画面に反映

この流れを、実際の 名前入力フォーム を題材にして、 ステップバイステップで追いかけていきます。

入力の流れを「一本の線」としてイメージする

まずは全体像を言葉でつかむ

Reactのフォームでは、 ユーザーが文字を入力してから画面に反映されるまでに、次のような流れが起きています。

  1. ユーザー入力
    • キーボードで文字を打つ
    • ブラウザが「入力された」というイベントを発生させる
  2. onChange
    • onChange に渡した関数が呼ばれる
    • イベントオブジェクト e から、入力された値を取り出す
  3. State更新
    • setState(例えば setName)を呼び出して、Stateを新しい値に更新する
  4. 画面に反映
    • 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

ここで起きていることをステップで説明します。

  1. ユーザーが入力欄に文字を打つ
  2. ブラウザが「入力された」というイベントを発生させる
  3. onChange={handleChange} によって、handleChange が呼ばれる
  4. 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

ここでの流れはこうです。

  1. ユーザーが文字を入力する
  2. handleChange が呼ばれる
  3. inputValue = e.target.value で入力された文字列を取り出す
  4. setName(inputValue) でState name を更新する
  5. 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} によって、入力欄の表示内容がState name に完全に紐づいていること
  • onChange で入力のたびにStateを更新していること

これにより、 入力欄は Controlled Component(制御されたコンポーネント) になります。

流れをもう一度まとめる

この名前入力フォームでは、 次のような流れが起きています。

  1. ユーザー入力
    • キーボードで文字を打つ
  2. onChange
    • handleChange が呼ばれる
    • e.target.value から入力値を取り出す
  3. State更新
    • setName(inputValue) でState name を更新する
  4. 画面に反映
    • 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ステップがすべて入っています。

それぞれを対応させると、こうなります。

  1. ユーザー入力jsx<input type="text" ... />
    • ユーザーがキーボードで文字を打つ場所です。
  2. onChangejsxonChange={handleChange}
    • 入力が変化した瞬間に呼ばれる関数を指定しています。
  3. State更新jsxconst handleChange = (e) => { const inputValue = e.target.value; setName(inputValue); };
    • e.target.value から入力値を取り出し、setName でStateを更新しています。
  4. 画面に反映jsxvalue={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" ... />
  • onChangeonChange={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

ここで起きていることを、流れに沿って整理します。

  1. ユーザー入力
    • ユーザーが入力欄に文字を打ちます。
  2. onChange
    • handleChange が呼ばれ、e.target.value から入力値を取り出します。
    • trim() で前後の空白を削除してから setName でStateを更新します。
  3. State更新
    • name が新しい値に変わります。
    • Reactが再レンダリングし、value={name}{name} の表示が更新されます。
  4. 画面に反映
    • 入力欄の中身が新しい name になります。
    • 「現在の名前」やメッセージの表示も更新されます。
    • isEmpty の値も変わり、ボタンの disabled やメッセージの内容が変わります。
  5. 送信処理
    • ユーザーが「送信」ボタンを押すと、handleSubmit が呼ばれます。
    • name が空ならアラートで警告し、空でなければ送信された名前を表示します。
    • 送信後に setName("") でStateをリセットし、フォームを初期状態に戻します。

ここまで来ると、「フォームとState」が実際のアプリの動きにかなり近づいています。

「入力→State→画面」の流れを、別の視点からもう一度見る

Controlled Componentとしての完成形

この名前入力フォームは、 典型的な Controlled Component になっています。

  • value={name} → 入力欄の表示は常にState name によって決まります。
  • 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連携など)が、 すべてこの型の応用として自然に組み立てられるようになっていきます。

タイトルとURLをコピーしました