React Hook FormのuseFieldArrayで現在の値を取得する方法
概要
React Hook Form の useFieldArray
は、フォームのフィールドを動的に追加・削除できる便利なフックです。
「現在の入力値を取得したい」と思ったときに、fields
を参照しても意図した値が得られないことがあります。
本記事では 「useFieldArray
の現在の値を正しく取得する方法」 を解説します!✨
1. useFieldArray で現在の値を取得するには?
useFieldArray
の fields
は、フォームの入力データそのものではなく、レンダリングのための情報を提供するものです。
したがって、以下のように fields
を直接使っても、リアルタイムな入力値は取得できません。
console.log(fields); // 現在の入力値は取得できない!
watch
を使う
✅ 正しく取得する方法 → useForm
には watch
という関数があり、フォームの現在の状態をリアルタイムで取得できます。
つまり、watch("items")
を使うことで、useFieldArray
の現在の値を簡単に取得できます!
watch
を使った実装例
2. 以下のコードでは、動的にフィールドを追加・削除しながら、リアルタイムで現在の入力値を表示しています。
import { useForm, useFieldArray } from "react-hook-form";
type FormValues = {
items: { name: string }[];
};
export default function MyForm() {
const { control, register, handleSubmit, watch } = useForm<FormValues>({
defaultValues: { items: [{ name: "" }] }
});
const { fields, append, remove } = useFieldArray({
control,
name: "items"
});
// ✅ 現在の値をリアルタイムで取得
const watchedItems = watch("items");
return (
<form onSubmit={handleSubmit((data) => console.log(data))}>
{fields.map((field, index) => (
<div key={field.id}>
<input {...register(`items.${index}.name`)} />
<button type="button" onClick={() => remove(index)}>削除</button>
</div>
))}
<button type="button" onClick={() => append({ name: "" })}>追加</button>
{/* ✅ 現在の値を表示 */}
<pre>現在の値: {JSON.stringify(watchedItems, null, 2)}</pre>
<button type="submit">送信</button>
</form>
);
}
watch
を使うメリット
3. watch("items")
を使うことで、以下のようなメリットがあります。
✅ リアルタイムに値を取得できる
-
useFieldArray
のfields
では取得できない「現在の入力データ」がすぐに取れる!
✅ 余計なステート管理が不要
-
useState
を使わなくてもwatch
だけで値を取得できるため、シンプルな実装が可能!
✅ フォーム全体の変更を即座にキャッチできる
-
watch
は他のフィールドの変更を監視できるので、フォーム全体のデータをリアルタイムで扱いたいときにも便利!
key
の設定について(補足)
4. React Hook Form の公式ドキュメントには、以下のような注意書きがあります。
The field.id (and not index) must be added as the component key to prevent re-renders breaking the fields:
(key
には index
ではなく field.id
を使うこと。そうしないと、再レンダリングでフィールドの内容が壊れる可能性がある)
実際に、以下のように index
を key
に使うと、削除時に入力内容がずれることがあります。
// ❌ index を key に使うのは NG!
{fields.map((field, index) => (
<div key={index}>
<input {...register(`items.${index}.name`)} />
</div>
))}
そこで、key
には field.id
を使うのが推奨されます。
// ✅ 正しい key の設定方法
{fields.map((field, index) => (
<div key={field.id}>
<input {...register(`items.${index}.name`)} />
</div>
))}
まとめ
✔ useFieldArray
の fields
では現在の値を取得できない
✔ リアルタイムな入力値を取得するには watch("items")
を使う
✔ watch
を使うと、余計なステート管理なしでフォームの値を取得できる
✔ key
には field.id
を使い、再レンダリング時の不具合を防ぐ
useFieldArray
で現在の値を取得する際に悩んでいる方は、ぜひ watch
を活用してみてください!
Discussion