LoginSignup
2

More than 1 year has passed since last update.

React Hook Formで動的にフォームを増やす。

Posted at

フォーム系のライブラリはいくつもありますが、動的なフォームは記法でつまづきがちなポイントだと思います。
今回は際レンダリング数が少なく、かなり使われ出しているReact Hook Formの動的なフォームのサンプルです。

まずは動的でないフォーム

こんな感じでOKだと思います。

interface sampleFormInterface {
  firstName: string
  lastName: string
}

const SampleComponent: React.FC = () => {
  const {
    register,
    handleSubmit,
  } = useForm<sampleFormInterface>()

  const onSubmit = (data: unknown) => {
    console.log(data)
  }

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input
        placeholder="Basic usage"
        {...register('firstName'}
      />
      <input
        placeholder="Basic usage"
        {...register('lastName'}
      />
    </form>
  )
}

useFormというフックを使って、使う関数やプロパティを準備しています。

種類も多いので、今回の記事ではドキュメントを置いておきます。

React Hook Form | register

useFieldArrayを使って動的に増やせるようにする。

配列対応させるにはuseFieldArrayを使います。
useFieldArrayのnameに配列名(例えばsampleForm)を設定して、
inputのresisterにsampleForm.${index}.firstNameのような形で設定します。

interface sampleFormInterface {
  firstName: string
  lastName: string
}

const SampleComponent: React.FC = () => {
  const {
    register,
    handleSubmit,
    control, // 追加
  } = useForm<sampleFormInterface>()

  // 追加
  const { fields, append } = useFieldArray({
    control,
    name: 'sampleForm',
    keyName: 'key', // デフォルトではidだが、keyに変更。
  })

  const onSubmit = (data: unknown) => {
    console.log(data)
  }

  // 追加
  const addInputForm = () => {
    append({ firstName: '', lastName: '' })
  }

  return (
    <>
      <form onSubmit={handleSubmit(onSubmit)}>
        {/* 変更 */}
        <ul>
          {fields.map((field, index) => (
            <li key={field.key} className="flex space-x-5">
              <input
                {...register(`sampleForm.${index}.firstName`)}
                placeholder="苗字"
              />
          <input
                {...register(`sampleForm.${index}.lastName`)}
                placeholder="名前"
              />
            </li>
          ))}
        </ul>
      </form>
      <button
        className="p-2 rounded-full bg-yellow-400"
        onClick={addInputForm}
      >
        追加ボタン
      </button>
    </>
  )
}

ネストさせたい場合は、
useFieldArrayのnameにsampleForm.${index}.nestedArrayのように設定して、
inputのresisterにsampleForm.${index}.nestedArray.${nestedIndex}.firstNameのような形で設定すればOKです。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2