Reactでフォームの入力パーツを使用する

Reactでフォームの入力パーツを使用する際の注意点をいくつかメモ。

サンプルコード

まずはinputをlabelと紐づける場合です。
通常のHTMLではinputにid属性、labelにfor属性を付けて紐づけますが、Reactの場合はfor属性の代わりにhtmlForを使います。

import { useState } from 'react'

function Form() {
  const [name, setName] = useState('');

  return (
    <form>
      <label htmlFor="name">名前</label>
      <input
        type="text"
        name="name"
        id="name"
        value={name}
        onChange={e => setName(e.target.value)}
      />
    </form>
  )
}

export default Form

htmlForを使用するデモページ

また紐づけの際、Reactで用意されているuseIdを使用すると一意のIDを生成できるので、競合を避けることができます。

import { useState, useId } from 'react'

function Form() {
  const [name, setName] = useState('');
  const nameId = useId();

  return (
    <form>
      <label htmlFor={nameId}>名前</label>
      <input
        type="text"
        name="name"
        id={nameId}
        value={name}
        onChange={e => setName(e.target.value)}
      />
    </form>
  )
}

export default Form

useIdを使用するデモページ

次にtextareaですが、値の指定をvalueに対して行います。
また通常のHTMLでは終了タグをつけますが、Reactの場合は終了タグは無しでの記述になります。

import { useState, useId } from 'react'

function Form() {
  const [message, setMessage] = useState('');
  const messageId = useId();

  return (
    <form>
      <label htmlFor={messageId}>メッセージ</label>
      <textarea
        name="message"
        id={messageId}
        value={message}
        onChange={e => setMessage(e.target.value)}
      />
    </form>
  )
}

export default Form

textareaのデモページ

次にラジオボタンで、ラジオボタンをループで表示する際、以下のように記述するとkeyの設定がないため警告が出ます。
ただ、フラグメントを<>~</>のように省略して記述している場合、<key=”xxx”>のようにkeyを記述するとエラーになります。

import { useState, useId } from 'react'

function Form() {
  const genderSelect = ['男性', '女性'];
  const [gender, setGender] = useState(genderSelect[0]);

  return (
    <form>
      {genderSelect.map(item => {
        const genderId = useId();
        return (
          <key={item}>
            <input
              type="radio"
              name="gender"
              id={genderId}
              value={item}
              checked={item === gender}
              onChange={e => setGender(e.target.value)}
            />
            <label htmlFor={genderId}>{item}</label>
          </>
        )
      })}
    </form>
  )
}

export default Form

そのため、Fragmentをインポートして省略しない形で記述する必要があります。

import { useState, useId, Fragment } from 'react'

function Form() {
  const genderSelect = ['男性', '女性'];
  const [gender, setGender] = useState(genderSelect[0]);

  return (
    <form>
      {genderSelect.map(item => {
        const genderId = useId();
        return (
          <Fragment key={item}>
            <input
              type="radio"
              name="gender"
              id={genderId}
              value={item}
              checked={item === gender}
              onChange={e => setGender(e.target.value)}
            />
            <label htmlFor={genderId}>{item}</label>
          </Fragment>
        )
      })}
    </form>
  )
}

export default Form

ラジオボタンのデモページ

次にチェックボックスの例です。
ラジオボタンの場合はグループ内で選択される値は1つでしたが、チェックボックスの場合は複数選択可能なため、値管理の配列内にチェックしているかどうかを管理する値を追加します。

import { useState, useId, Fragment } from 'react'

function Form() {
  const [contact, setContact] = useState([
    {
      label: 'メール',
      checked: false
    }, {
      label: '電話',
      checked: false
    }, {
      label: 'FAX',
      checked: false
    }
  ]);
  const handleContactChange = (e) => {
    const updateContact = contact.map((item) => {
      const cloneItem = { ...item };
      if(cloneItem.label === e.target.value) {
        cloneItem.checked = !cloneItem.checked;
      }
      return cloneItem;
    });
    setContact(updateContact);
  }

  return (
    <form>
      {contact.map(item => {
        const contactId = useId();
        return (
          <Fragment key={item.label}>
            <input
              type="checkbox"
              name="contact"
              id={contactId}
              value={item.label}
              checked={item.checked}
              onChange={handleContactChange}
            />
            <label htmlFor={contactId}>{item.label}</label>
          </Fragment>
        )
      })}
    </form>
  )
}

export default Form

チェックボックスのデモページ

最後にselectですが、通常HTMLでは選択している項目(option)に対してselectedを付与しますが、Reactの場合は選択中の項目のvalueをselectのvalueに指定します。

import { useState, useId, Fragment } from 'react'

function Form() {
  const areaSelect = ['北海道', '東北', '関東', '中部', '近畿', '中国', '四国', '九州'];
  const [area, setArea] = useState(areaSelect[0]);
  const areaId = useId();

  return (
    <form>
      <label htmlFor={areaId}></label>
      <select
        name="area"
        id={areaId}
        value={area}
        onChange={e => setArea(e.target.value)}
      >
        {areaSelect.map(item => {
          return (
            <option
              key={item}
              value={item}
            >{item}</option>
          )
        })}
      </select>
    </form>
  )
}

export default Form

selectのデモページ

今回試した内容の一式は以下の通りです。

import { useState, useId, Fragment } from 'react'

function Form() {
  const [name, setName] = useState('');
  const nameId = useId();
  const [message, setMessage] = useState('');
  const messageId = useId();
  const genderSelect = ['男性', '女性'];
  const [gender, setGender] = useState(genderSelect[0]);
  const [contact, setContact] = useState([
    {
      label: 'メール',
      checked: false
    }, {
      label: '電話',
      checked: false
    }, {
      label: 'FAX',
      checked: false
    }
  ]);
  const handleContactChange = (e) => {
    const updateContact = contact.map((item) => {
      const cloneItem = { ...item };
      if(cloneItem.label === e.target.value) {
        cloneItem.checked = !cloneItem.checked;
      }
      return cloneItem;
    });
    setContact(updateContact);
  }
  const areaSelect = ['北海道', '東北', '関東', '中部', '近畿', '中国', '四国', '九州'];
  const areaId = useId();
  const [area, setArea] = useState(areaSelect[0]);

  return (
    <form>
      <label htmlFor={nameId}>名前</label>
      <input
        type="text"
        name="name"
        id={nameId}
        value={name}
        onChange={e => setName(e.target.value)}
      />

      <label htmlFor={messageId}>メッセージ</label>
      <textarea
        name="message"
        id={messageId}
        value={message}
        onChange={e => setMessage(e.target.value)}
      />

      {genderSelect.map(item => {
        const genderId = useId();
        return (
          <Fragment key={item}>
            <input
              type="radio"
              name="gender"
              id={genderId}
              value={item}
              checked={item === gender}
              onChange={e => setGender(e.target.value)}
            />
            <label htmlFor={genderId}>{item}</label>
          </Fragment>
        )
      })}

      {contact.map(item => {
        const contactId = useId();
        return (
          <Fragment key={item.label}>
            <input
              type="checkbox"
              name="contact"
              id={contactId}
              value={item.label}
              checked={item.checked}
              onChange={handleContactChange}
            />
            <label htmlFor={contactId}>{item.label}</label>
          </Fragment>
        )
      })}

      <label htmlFor={areaId}></label>
      <select
        name="area"
        id={areaId}
        value={area}
        onChange={e => setArea(e.target.value)}
      >
        {areaSelect.map(item => {
          return (
            <option
              key={item}
              value={item}
            >{item}</option>
          )
        })}
      </select>
    </form>
  )
}

export default Form

一式のデモページ

参考サイト

このエントリーをはてなブックマークに追加

関連記事

コメントを残す

メールアドレスが公開されることはありません。
* が付いている欄は必須項目です

CAPTCHA


コメントが承認されるまで時間がかかります。

2024年12月
1234567
891011121314
15161718192021
22232425262728
293031