Reactでフォームを扱う方法についてまとめました【React/Input/Radio/Select】

JavaScript

Reactでフォームの部品を扱う際、HTMLの感覚で書いているとうまく動作せずハマる時があります。Reactのお作法的な書き方もあるので、そのまま覚える型としてメモしておきます。

テキストフィールド<input type=”text”>

input type=”text”は、次のような単一行のテキスト入力欄を生成します。

入力した値がリアルタイムで反映されるサンプルを作成しました。

const ContentArea = () => {
  // 選択した値を管理(初期値:””)
  const [val, setVal] = React.useState('');

  // テキストフィールドの値がチェンジされた時
  const handleChange = (e) => {
    setVal(e.target.value);
  };

  return (
    <>
      <h2>テキストフィールド</h2>

      <div className="container">
        <input type="text" value={val} onChange={handleChange} />
        <p>入力値:{val}</p>
      </div>
    </>
  );
};

実際の動作はこちらで確認できます。

See the Pen react-form-text by donguri2020 (@m-ke) on CodePen.

inputタグのvalue属性にはuseStateで管理している値を渡す

ポイントとなるところをメモしておきます。
まず、Reactではフォームに入力した値をuseStateで管理することが多いです。

inputタグのvalue属性には、useStateで管理している値(ここではval)を設定し、入力値が変更されたらuseStateの更新関数(ここではsetVal)で値を更新します。

const ContentArea = () => {
    // useStateで管理している値
    const [val, setVal] = React.useState('');

    // テキストフィールドの値がチェンジされた時
    const handleChange = (e) => {
        setVal(e.target.value);
    };

    return (
        <input type="text" value={val} onChange={handleChange} />
    )
}

これで入力値がリアルタイムで反映されます。

ラジオボタン<input type=”radio”>

input type=”radio”は、ラジオボタンを生成します。ラジオボタンは、単一の項目しか選択できないのが特徴です。

ラジオボタンが複数の場合、次のように、要素を配列で管理してArray.map()で取り出すことが多いです。

  // データ
  const items = ["アイテム1", "アイテム2", "アイテム3", "アイテム4"]

以下は、ラジオボタンの「その他」が選択された時、テキストフィールドが表示されるサンプルです。

const ContentArea = () => {
  // データ
  const items = ['アイテム1', 'アイテム2', 'アイテム3', 'その他'];

  // 選択した値を管理(初期値:ラジオ1)
  const [val, setVal] = React.useState('アイテム1');

  // ラジオボタンの値がチェンジされた時
  const handleChange = (e) => {
    setVal(e.target.value);
  };

  return (
    <>
      <h2>ラジオボタン</h2>
      <p className="center">「その他」を選択したら入力欄が表示されます</p>
      <div className="container">
        {items.map((item) => {
          return (
            <div key={item}>
              <input
                id={item}
                type="radio"
                value={item}
                onChange={handleChange}
                checked={item === val}
              />
              <label htmlFor={item}>{item}</label>
            </div>
          );
        })}

        <p>選択したのは「{val}」です。</p>
        {val === 'その他' && (
          <p>
            <input type="text" />
          </p>
        )}
      </div>
    </>
  );
};

ReactDOM.render(<ContentArea />, document.getElementById('root'));

実際の動作はこちらで確認できます。

See the Pen react-form-radio by donguri2020 (@m-ke) on CodePen.

ラジオボタンのチェック状態はuseStateで管理する

ラジオボタンをチェックしたcheckedの状態は、useState()で管理します。useStateの初期値を設定しておけば、読み込み時にラジオボタンを選択された状態で表示できます。

次のようにuseStateで初期値を設定します。

  // 選択した値を管理(初期値:ラジオ1)
  const [val, setVal] = React.useState("アイテム1")

inputのradioボタンの値がuseStateの値と同じだったら、input属性のcheckedをtrueにして、選択した状態にします。

以下はinputタグの必要な箇所だけを抜き出しました。

<input type="radio" value={item} onChange={handleChange} checked={item === val} />

labelタグのfor属性はhtmlForにする

フォームには、特定のラベルをinput属性に紐づける機能があります。具体的には、ラジオボタンに紐づけたテキストをクリックすると、ラジオボタンが選択される。といったことができます

HTMLは、label要素のfor属性とinputのid属性を同じ名前にして紐付けます。
Reactの場合、for属性ではなくhtmlFor属性で設定します。

// HTML
<input type="radio" id="item1" value="item1" checked />
<label for="item1">アイテム1</label>

// React
<input type="radio" id="item1" value="item1" checked />
<label htmlFor="item1">アイテム1</label>

余談ですが、for属性を設定しなくても<label>でinputタグを囲めば同様の効果が得られます。

<label>
    <input type="radio" id="item1" value="item1" checked />
    アイテム1
</label>

チェックボックス<input type=”checkbox”>

input type=”checkbox”は、チェックボックスを生成します。ラジオボタンと異なり、複数選択できるのが特徴です。


チェックボックスの項目が複数ある場合、要素を配列で管理します。
配列はuseStateで状態を管理します。配列の要素はオブジェクトにします。プロパティは項目名の「label」、チェック状態を管理する「checked」の2つを設定します。
※「checked」の初期値はfalseです。

  const [itemData, setItemData] = React.useState([
    { label: "商品1", checked: false },
    { label: "商品2", checked: false },
    { label: "商品3", checked: false }
  ]);

Array.map()で要素を取り出し、チェックボックスの値として表示します。

以下は、選択した項目がチェックボックスの下に表示されるようにしたサンプルです。

const ContentArea = () => {
  const [itemData, setItemData] = React.useState([
    { label: "商品1", checked: false },
    { label: "商品2", checked: false },
    { label: "商品3", checked: false }
  ]);
  // 選択した値を管理(初期値:””)
  const [checkList, setCheckList] = React.useState([]);

  // テキストフィールドの値がチェンジされた時
  const handleChange = (e) => {
    const newItem = [...itemData];
    newItem.map((item) => {
      if (item.label === e.target.value) {
        item.checked = !item.checked;
      }
      return newItem;
    });

   // 選択した項目を更新する
    setItemData(newItem);

   // 選択した項目だけをフィルターで抜き出す
    const checkItem = newItem.filter((item) => item.checked);
    setCheckList(checkItem);
  };

  return (
    <>
      <h2>チェックボックス</h2>

      <div className="container">
        {itemData.map((item) => {
          return (
            <div key={item.label}>
              <input
                type="checkbox"
                id={item.label}
                value={item.label}
                onChange={handleChange}
              />
              <label htmlFor={item.label}>{item.label}</label>
            </div>
          );
        })}

        <p>
          チェックした値:
          {checkList.map((item) => {
            return <span key={item.label}>{item.label}</span>;
          })}
        </p>
      </div>
    </>
  );
};

実際の動作はこちらで確認できます。

See the Pen react-form-checkbox by donguri2020 (@m-ke) on CodePen.

チェックボックスのチェック状態はuseStateで管理する

以下はチェックボックスの値が変更された時に呼び出される関数です。
e.target.valueには変更したチェックボックスのvalue値が格納されています。

// テキストフィールドの値がチェンジされた時
  const handleChange = (e) => {
    const newItem = [...itemData];
    newItem.map((item) => {
      if (item.label === e.target.value) {
        item.checked = !item.checked;
      }
      return newItem;
    });

   // 選択した項目を更新する
    setItemData(newItem);
}

まず、チェックボックスの配列をコピーして変数newItemに格納します。Array.map()でコピーした配列の要素を一つずつ取り出して処理していきます。

オブジェクトのlabelプロパティと.target.valueの値が同じ場合、checkedプロパティの真偽を反対にします。この配列をuseStateの更新関数setItemData()で更新します。
※チェックボックスの配列は新しく作らなくても動作すると思いますが、変更した値を返却するような動きは、あたらしく配列を作り直した方がバグを防げるそうです。

プルダウンメニュー<select>

selectは、プルダウンメニューを生成します。選択肢の多い項目を作成する際に使用することが多いです。

プルダウンのメニューは配列で管理します。

  // メニューデータ
  const items = ["アイテム1", "アイテム2", "アイテム3"];

以下は選択したメニューがプルダウンの下に表示されるサンプルです。

const ContentArea = () => {
  // メニューデータ
  const items = ["アイテム1", "アイテム2", "アイテム3"];

  // プルダウンの値を管理(初期値:アイテム1)
  const [seleceItem, setSelectItem] = React.useState("アイテム1");

  // プルダウンがチェンジされた時
  const handleChange = (e) => {
    setSelectItem(e.target.value);
  };

  return (
    <>
      <h2>プルダウン</h2>

      <div className="container">
        <section>
          <select value={seleceItem} onChange={handleChange}>
            {items.map((item) => (
              <option key={item} value={item}>
                {item}
              </option>
            ))}
          </select>
        </section>

        <p>選択した値:{seleceItem}</p>
      </div>
    </>
  );
};

実際の動作はこちらで確認できます。

See the Pen react-form-pulldown by donguri2020 (@m-ke) on CodePen.

プルダウンの初期値を設定する

プルダウンの初期値を設定する場合、HTMLではoptionタグにselected属性を設定します。
Reactの場合、以下のようにoptionタグではなく、selectタグにvalueを設定します。

// 初期値をアイテム3にする
<select value="アイテム3">
    <option value="アイテム1">アイテム1</option>
    <option value="アイテム2">アイテム2</option>
    <option value="アイテム3">アイテム3</option>
</select>

まとめ

今回、Reactでフォームを扱う方法について調べました。useStateで値を管理することが多いので、最初は慣れませんでした、、。選択状態を表すselected属性の設定方法もHTMLと少し異なります。

忘れた時、ここからコピペして使おうと思います!