コンテンツにスキップ

useFieldArray

フィールド配列のためのReactフック

useFieldArray UseFieldArrayProps

フィールド配列(動的フォーム)を扱うためのカスタムフック。モチベーションは、より良いユーザーエクスペリエンスとパフォーマンスを提供することです。パフォーマンスの向上を視覚化するには、 この短いビデオ をご覧ください。

プロパティ

名前必須説明
namestring

フィールド配列の名前。注意:動的な名前はサポートしていません。

controlObjectcontrol useFormによって提供されるオブジェクト。FormProviderを使用している場合はオプションです。
shouldUnregisterboolean

アンマウント後にフィールド配列を登録解除するかどうか。

keyNamestring = id

keyプロパティとして使用する自動生成された識別子を持つ属性の名前。このプロパティは不要になり、次のメジャーバージョンで削除されます。

rulesObject

同じ検証rulesAPI registerに対して、以下を含みます。

required、minLength、maxLength、validate

useFieldArray({
rules: { minLength: 4 }
})

検証エラーが発生した場合、rootプロパティは formState.errors?.fieldArray?.rootに、次の型で追加されます。 FieldError

重要:これは、組み込み検証のみに適用されます。

function FieldArray() {
const { control, register } = useForm();
const { fields, append, prepend, remove, swap, move, insert } = useFieldArray({
control, // control props comes from useForm (optional: if you are using FormProvider)
name: "test", // unique name for your Field Array
});
return (
{fields.map((field, index) => (
<input
key={field.id} // important to include key with field's id
{...register(`test.${index}.value`)}
/>
))}
);
}

戻り値

名前説明
fieldsobject &{ id: string }このobjectには、コンポーネントのdefaultValue keyが含まれています。
append(obj: object | object[], focusOptions) => void

フィールドの末尾に入力/入力を追加し、フォーカスします。このアクション中に入力値が登録されます。

重要:追加データは必須であり、部分的なものではありません。

prepend(obj: object | object[], focusOptions) => void

フィールドの先頭に入力/入力を追加し、フォーカスします。このアクション中に入力値が登録されます。

重要:prependデータは必須であり、部分的なものではありません。

insert(index: number, value: object | object[], focusOptions) => void

特定の位置に入力/入力を挿入し、フォーカスします。

重要:挿入データは必須であり、部分的なものではありません。

swap(from: number, to: number) => void入力/入力の位置を入れ替えます。
move(from: number, to: number) => void入力/入力を別の位置に移動します。
update(index: number, obj: object) => void

特定の位置にある入力/入力を更新します。更新されたフィールドはアンマウントされて再マウントされます。これが望ましくない場合は、 setValue APIの代わりに。

重要:更新データは必須であり、部分的なものではありません。

replace(obj: object[]) => voidフィールド配列全体の値を置き換えます。
remove(index?: number | number[]) => void特定の位置にある入力/入力を削除するか、インデックスが指定されていない場合はすべて削除します。

ルール

  • useFieldArrayは、keyに使用されるidという名前の一意の識別子を自動的に生成します。prop。これがなぜ必要なのかの詳細については、 https://react.dokyumento.jp/learn/rendering-lists

    再レンダリングによってフィールドが壊れるのを防ぐために、コンポーネントキーとしてfield.idindexではなく)を追加する必要があります。

    // ✅ correct:
    {fields.map((field, index) => <input key={field.id} ... />)}
    // ❌ incorrect:
    {fields.map((field, index) => <input key={index} ... />)}

  • アクションを次々と積み重ねないことをお勧めします。

    onClick={() => {
    append({ test: 'test' });
    remove(0);
    }}
    // ✅ Better solution: the remove action is happened after the second render
    React.useEffect(() => {
    remove(0);
    }, [remove])
    onClick={() => {
    append({ test: 'test' });
    }}
  • useFieldArrayは一意であり、独自の状態更新を持っています。つまり、同じnameを持つ複数のuseFieldArrayを持つべきではありません。

  • 各入力名は一意である必要があります。同じ名前でチェックボックスまたはラジオを作成する必要がある場合は、useControllerまたはControllerで使用します。

  • フラットフィールド配列はサポートされていません。

  • フィールド配列を追加、先頭に追加、挿入、更新する場合、objは空のオブジェクトではなく、すべての入力のdefaultValuesを指定する必要があります。

    append();
    append({});
    append({ firstName: 'bill', lastName: 'luo' });

TypeScript

  • 入力nameを登録するときは、次のようにキャストする必要があります。 const

    <input key={field.id} {...register(`test.${index}.test` as const)} />
  • 循環参照はサポートされていません。詳細については、こちらの Githubの問題 を参照してください。

  • ネストされたフィールド配列の場合、その名前でフィールド配列をキャストする必要があります。

    const { fields } = useFieldArray({ name: `test.${index}.keyValue` as 'test.0.keyValue' });

CodeSandbox JS
import React from "react";
import { useForm, useFieldArray } from "react-hook-form";
function App() {
const { register, control, handleSubmit, reset, trigger, setError } = useForm({
// defaultValues: {}; you can populate the fields by this attribute
});
const { fields, append, remove } = useFieldArray({
control,
name: "test"
});
return (
<form onSubmit={handleSubmit(data => console.log(data))}>
<ul>
{fields.map((item, index) => (
<li key={item.id}>
<input {...register(`test.${index}.firstName`)} />
<Controller
render={({ field }) => <input {...field} />}
name={`test.${index}.lastName`}
control={control}
/>
<button type="button" onClick={() => remove(index)}>Delete</button>
</li>
))}
</ul>
<button
type="button"
onClick={() => append({ firstName: "bill", lastName: "luo" })}
>
append
</button>
<input type="submit" />
</form>
);
}
import * as React from "react";
import { useForm, useFieldArray, useWatch } from "react-hook-form";
export default function App() {
const { control, handleSubmit } = useForm();
const { fields, append, update } = useFieldArray({
control,
name: 'array'
});
return (
<form onSubmit={handleSubmit((data) => console.log(data))}>
{fields.map((field, index) => (
<Edit
key={field.id}
control={control}
update={update}
index={index}
value={field}
/>
))}
<button
type="button"
onClick={() => {
append({ firstName: "" });
}}
>
append
</button>
<input type="submit" />
</form>
);
}
const Display = ({ control, index }) => {
const data = useWatch({
control,
name: `array.${index}`
});
return <p>{data?.firstName}</p>;
};
const Edit = ({ update, index, value, control }) => {
const { register, handleSubmit } = useForm({
defaultValues: value
});
return (
<div>
<Display control={control} index={index} />
<input
placeholder="first name"
{...register(`firstName`, { required: true })}
/>
<button
type="button"
onClick={handleSubmit((data) => update(index, data))}
>
Submit
</button>
</div>
);
};
import React from 'react';
import { useForm, useWatch, useFieldArray, Control } from 'react-hook-form';
type FormValues = {
data: { name: string }[];
};
const ConditionField = ({
control,
index,
register,
}: {
control: Control<FormValues>;
index: number;
}) => {
const output = useWatch({
name: 'data',
control,
defaultValue: 'yay! I am watching you :)',
});
return (
<>
{output[index]?.name === "bill" && (
<input {...register(`data[${index}].conditional`)} />
)}
<input
{...register(`data[${index}].easyConditional`)}
style={{ display: output[index]?.name === "bill" ? "block" : "none" }}
/>
</>
);
};
const UseFieldArrayUnregister: React.FC = () => {
const { control, handleSubmit, register } = useForm<FormValues>({
defaultValues: {
data: [{ name: 'test' }, { name: 'test1' }, { name: 'test2' }],
},
mode: 'onSubmit',
shouldUnregister: false,
});
const { fields } = useFieldArray({
control,
name: 'data',
});
const onSubmit = (data: FormValues) => console.log(data);
return (
<form onSubmit={handleSubmit(onSubmit)}>
{fields.map((data, index) => (
<>
<input {...register(`data[${index}].name`)} />
<ConditionField control={control} register={register} index={index} />
</>
))}
<input type="submit" />
</form>
);
};
import React from 'react';
import { useForm, useFieldArray } from 'react-hook-form';
const App = () => {
const { register, control } = useForm<{
test: { value: string }[];
}>({
defaultValues: {
test: [{ value: '1' }, { value: '2' }],
},
});
const { fields, prepend, append } = useFieldArray({
name: 'test',
control,
});
return (
<form>
{fields.map((field, i) => (
<input key={field.id} {...register(`test.${i}.value` as const)} />
))}
<button
type="button"
onClick={() => prepend({ value: '' }, { focusIndex: 1 })}
>
prepend
</button>
<button
type="button"
onClick={() => append({ value: '' }, { focusName: 'test.0.value' })}
>
append
</button>
</form>
);
};

ビデオ

次のビデオでは、基本的な使い方を説明します。 useFieldArray.

ヒント

カスタム登録

Controllerで入力をregisterすることもできます。実際の入力なし。これにより、useFieldArrayは複雑なデータ構造で使用したり、実際のデータが入力内に保存されていない場合でも、すばやく柔軟に使用できるようになります。

import { useForm, useFieldArray, Controller, useWatch } from "react-hook-form";
const ConditionalInput = ({ control, index, field }) => {
const value = useWatch({
name: "test",
control
});
return (
<Controller
control={control}
name={`test.${index}.firstName`}
render={({ field }) =>
value?.[index]?.checkbox === "on" ? <input {...field} /> : null
}
/>
);
};
function App() {
const { control, register } = useForm();
const { fields, append, prepend } = useFieldArray({
control,
name: "test"
});
return (
<form>
{fields.map((field, index) => (
<ConditionalInput key={field.id} {...{ control, index, field }} />
))}
</form>
);
}

制御されたフィールド配列

フィールド配列全体を制御したい場合があります。つまり、各onChangeがfieldsオブジェクトに反映されます。

import { useForm, useFieldArray } from "react-hook-form";
export default function App() {
const { register, handleSubmit, control, watch } = useForm<FormValues>();
const { fields, append } = useFieldArray({
control,
name: "fieldArray"
});
const watchFieldArray = watch("fieldArray");
const controlledFields = fields.map((field, index) => {
return {
...field,
...watchFieldArray[index]
};
});
return (
<form>
{controlledFields.map((field, index) => {
return <input {...register(`fieldArray.${index}.name` as const)} />;
})}
</form>
);
}

ご支援ありがとうございます

React Hook Formがあなたのプロジェクトで役立つ場合は、スターを付けてサポートしてください。