🌴
【React】React Hook FormのuseFieldArrayで配列配下の項目のエラーを取得
概要
reactでフォーム入力のライブラリReact Hook Form
では、可変の配列項目を格納できるuseFieldArray
という機能があります。このuseFieldArray
で配列配下の項目がバリデーションエラーになった時に、そのエラーをどう取得するかというメモ書きです。
前提
- React Hook Formのバージョンはv7系とします。
- useFieldArrayの機能概要については、以下のドキュメントや記事を参照ください。
useFieldArrayの公式ドキュメント
【備忘録】React Hook Form(v7)を使って、ネストされたフォームを実装する
対応
Dynamically add errors when using useFieldArray with React Hook Formのstackoverflowの記事で対応が紹介されている通り、errors.items.index.name
の形式でエラーを参照することができます。
実装サンプル
用意した配列(sampleRecords)へ、テキスト項目(name)を入力するものを、サンプルとして実装します。
まずは配列の定義部分の実装です。
SampleNameInputComponent.js
import { useEffect } from "react";
import useSWR from "swr";
import { useFieldArray, useForm } from "react-hook-form";
import toast from "react-hot-toast";
import SampleNameInputComponent from "./input/SampleNameInputComponent";
export default function SampleArrayComponent() {
const filedArrayName = "sampleRecords";
const { control, register, formState } = useForm({
mode: "onChange",
});
const { fields, replace } = useFieldArray({
control,
name: filedArrayName,
});
const { data: sampleRecords } = useSWR("/getRecords", async () => {
// API経由で初期値を取得(記載は割愛)
const result = await getFromAPI();
if (result.status != 200) {
toast.error("データの取得に失敗しました", {
duration: 3000,
});
return undefined;
} else {
return result.data;
}
});
useEffect(() => {
if (sampleRecords) {
// 取得したデータをフォームに設定
replace(
sampleRecords.map((record) => {
return {
name: record.name,
};
})
);
}
}, [sampleRecords]);
return (
<>
{sampleRecords && (
<>
{fields.map((_, index) => (
<div>
<SampleNameInputComponent
fieldArrayName={filedArrayName}
fieldName="name"
index={index}
register={register}
errors={formState.errors}
/>
</div>
))}
</>
)}
</>
);
}
次はテキストボックスのコンポーネントの実装です。ここでエラーの表示を行います。
SampleNameInputComponent.js
export default function SampleNameInputComponent(prop) {
const fieldName = `${prop.fieldArrayName}.${prop.index}.${prop.fieldName}`;
// エラーメッセージの取得
const errorMessage =
prop.errors?.[prop.fieldArrayName]?.[prop.index]?.[prop.fieldName]?.message;
return (
<>
<input
id={fieldName}
type="text"
name={fieldName}
{...prop.register(fieldName, {
required: "名前は必須項目です",
maxLength: {
value: 300,
message: "300文字以下で入力してください",
},
})}
/>
{errorMessage && <div>{errorMessage}</div>}
</>
);
}
Discussion
フォームデータ定義のうち、配列リストの単一アイテムごとにzodで外出したバリデーション結果を表示するようなサンプルを作ってみました。
簡単ですが、以上です。
ありがとうございます。
zodで外出しすると、コードが整理されて綺麗になりますね。