はじめに
この記事では、Reactにおいてフォームのバリデーション管理ができる、React-Hook-Form
ライブラリ(以降はRHF)において、プリミティブ型の配列のバリデーションを行う方法について記述します。
対象となる方
- react-hook-formを利用して、string[]のような、動的な配列のバリデーションをしたい人
Reack Hook Formとは
Reack Hook Form(以降はRHF)とは、Reactアプリケーションにおいて、フォームのバリデーションを簡単に実装できるライブラリです。
その中で、動的な配列を簡単に実装できるフックとして、useFieldArray()
が提供されています。
https://react-hook-form.com/docs/usefieldarray
useFieldArray
ドキュメントのexampleにあるように、fields
が配列自体、append
・remove
が配列に要素追加・削除する関数として取得できます。
これによって、TODOリストや参加者リストなど、配列の要素数が定まっていない値に対しても、RHFによるバリデーションの恩恵を受けることができます。
export const FieldArray = () => {
const { register, control } = useForm({
defaultValues: {name: 'defaultUser', age: 18}
});
const { fields, append, remove } = useFieldArray({
control,
name: "hogeList"
});
const handleAdd = () => {
append({name: 'testUser', age: 20})
}
return (
<>
{fields.map((item, index) => (
<div key={item.id}>
<input {...register(`hogeList.${index}.name`)} />
<input {...register(`hogeList.${index}.age`)} />
<button type="button" onClick={() => remove(index)}>Delete</button>
</div>
))}
<button type="button" onClick={handleAdd}>ADD</button>
</>
);
}
ただし、useFieldArray
が利用可能な配列の種類は、オブジェクトの配列のみです。つまり、キーとバリューを持つデータ構造でなければなりません。
問題点
先の説明の際に、useFieldArray
を利用することで、TODOリストもバリデーション可能となると述べました。
ただし、useFieldArray
を利用するには、プリミティブの配列ではなく、オブジェクトの配列にする必要があります。
1. todoList: string[] // プリミティブの配列では動かない
2. todoList: { title: string }[] // オブジェクトの配列は動く
2番の実装のように、オブジェクトのvalueを管理したい値にすることで、useFieldArray
を利用したバリデーションを実装することは可能です。
しかし、TODOリストとしての仕様は、文字列の配列で満たすことができるはずです。
それが、ライブラリの都合のみによって、実装が変わってしまうことは、可能であれば避けたいなと個人的には思います。
そこで、まずは簡単な解決策を考えてみました。
useFieldArray
使わずにmap
でゴリ押すパターンです。
実装例
export const TodoList = () => {
const { register, setValue } = useForm({
defaultValues: { list: [''] }
});
return (
<>
{list.map((value: string, index: number) => {
return (
<>
<input key={index} {...register(value)} />
<button onClick={() => setValue('list', details.toSpliced(index, 1))} >Delete</>
</>
)
})}
<button onClick={() => setValue('list', [...list, ''])}>Add</button>
</>
}
ただし、削除・挿入の際に起きる再レンダリング範囲が、useFormを利用してバリデーション実装をしているコンポーネントすべてになってしまうという課題が存在してしまいます...。
フォームの部品すべてが再レンダリングの範囲に含まれてしまうことは、特にフォームの入力要素数が多い場合には、望ましいことではありません。
結論
この記事では、RHFを利用して、動的なプリミティブの配列を扱うときの実装方法について述べていきました。
実現方法としては2つ存在しています。
- 管理したい値をvalueとしたオブジェクト型にして、
useFieldArray
を利用する -
useFieldArray
を利用せずに、mapを用いる
それぞれ、メリット・デメリットが存在するため、管理するフォームの規模や実装方針に合わせて選定すると良いと思いました。