🦊

【React Hook Form】useFieldArrayの使い方

2023/05/05に公開1

概要

Reactでフォームを実装する際にはReact Hook Formを使っているのですが、要素が可変のフォームを実装したのでまとめておきます。
結論としてはuseFieldArrayを使うことで実現できました。
https://react-hook-form.com/api/usefieldarray/#main

基本

import { useForm, useFieldArray } from 'react-hook-form';

export const FormComponent = () => {
  const { register, handleSubmit, control } = useForm({
    defaultValues: {
      emails: [{ email: '' }],
    },
  });
  const { fields, append } = useFieldArray({
    name: 'emails',
    control,
  });

  const onSubmit = (data) => {
    const { emails } = data;
    console.log(emails);
  };

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <div>
        {fields.map((field, index) => (
          <>
            <input
              key={field.id}
              type="email"
              {...register(`emails.${index}.email`)}
            />
          </>
        ))}
      </div>
      <button type="button" onClick={() => append({ email: '' })}>
        add
      </button>
      <button type="submit">submit</button>
    </form>
  );
};

useFieldArrayにはuseFormのcontrollと、一意のnameを指定します。
fieldsには配列が入っているので、それをmapで展開します。その際にkeyにはindexではなくfield.idを指定しましょう。
要素を追加する場合はuseFieldArrayから返ってくるappendを使うことでfieldsに追加できます。

要素の削除

import { useForm, useFieldArray } from 'react-hook-form';

export const FormComponent = () => {
  const { register, handleSubmit, control } = useForm({
    defaultValues: {
      emails: [{ email: '' }],
    },
  });
  const { fields, append, remove } = useFieldArray({
    name: 'emails',
    control,
  });

  const onSubmit = (data) => {
    const { emails } = data;
    console.log(emails);
  };

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <div>
        {fields.map((field, index) => (
          <>
            <input
              key={field.id}
              type="email"
              {...register(`emails.${index}.email`)}
            />
            <button type="button" onClick={() => remove(index)}>
              remove
            </button>
          </>
        ))}
      </div>
      <button type="button" onClick={() => append({ email: '' })}>
        add
      </button>
      <button type="submit">submit</button>
    </form>
  );
};

要素を削除したい場合はremoveを使用します。
removeはどの要素を削除するのかを引数に指定できるので、indexを指定します。

要素を入れ替える

import { useForm, useFieldArray } from 'react-hook-form';

export const FormComponent = () => {
  const { register, handleSubmit, control } = useForm({
    defaultValues: {
      emails: [{ email: '' }],
    },
  });
  const { fields, append, remove, replace } = useFieldArray({
    name: 'emails',
    control,
  });

  const onSubmit = (data) => {
    const { emails } = data;
    console.log(emails);
  };

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <div>
        {fields.map((field, index) => (
          <>
            <input
              key={field.id}
              type="email"
              {...register(`emails.${index}.email`)}
            />
            <button type="button" onClick={() => remove(index)}>
              remove
            </button>
          </>
        ))}
      </div>
      <button type="button" onClick={() => append({ email: '' })}>
        add
      </button>
      <button
        type="button"
        onClick={() => {
          replace([{ email: 'new email' }]);
        }}
      >
        replace
      </button>
      <button type="submit">submit</button>
    </form>
  );
};

要素を新しく入れ替えたい場合はreplaceを使用します。
replaceを使うことでfieldsに入っている値を削除して、新しい値を格納できます。
replaceの引数には新しく格納する値を指定しましょう。
自分の場合はAPIから取得したデータをもとに新たにフォーム要素を差し替えたい場面があったのでreplaceを使用しました。

Discussion