useFieldArray UseFieldArrayProps
用于处理字段数组(动态表单)的自定义钩子。其目的是为了提供更好的用户体验和性能。你可以观看 这段简短的视频 来直观感受性能的提升。
属性
名称 | 类型 | 必填 | 描述 |
---|---|---|---|
name | 字符串 | ✓ | 字段数组的名称。注意:不支持动态名称。 |
control | 对象 | control 由 useForm 提供的对象。如果使用 FormProvider,则可选。 | |
shouldUnregister | 布尔值 | 卸载后是否注销字段数组。 | |
keyName | 字符串 = id | 用于作为 | |
rules | 对象 | 与 register 相同的验证 required, minLength, maxLength, validate
如果出现验证错误,则 重要:这仅适用于内置验证。 |
示例
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) => (<inputkey={field.id} // important to include key with field's id{...register(`test.${index}.value`)}/>))});}
返回
名称 | 类型 | 描述 |
---|---|---|
fields | 对象 &{ id: 字符串 } | 此 object 包含 defaultValue 和 key 用于你的组件。 |
append |
| 将输入/输入追加到字段的末尾并聚焦。输入值将在执行此操作期间注册。 重要:需要追加数据,不能是部分数据。 |
prepend | (obj: object | object[], focusOptions) => void | 将输入/输入添加到字段的开头并聚焦。输入值将在执行此操作期间注册。 重要:需要添加数据,不能是部分数据。 |
insert | (index: number, value: object | object[], focusOptions) => void | 在特定位置插入输入/输入并聚焦。 重要:需要插入数据,不能是部分数据。 |
swap |
| 交换输入/输入位置。 |
move |
| 将输入/输入移动到另一个位置。 |
update |
| 更新特定位置的输入/输入,更新的字段将被卸载并重新安装。如果不需要此行为,请使用 重要:需要更新数据,不能是部分数据。 |
replace |
| 替换整个字段数组的值。 |
remove |
| 删除特定位置的输入/输入,或在未提供索引时删除所有输入/输入。 |
规则
useFieldArray
自动生成一个名为id
的唯一标识符,用于key
属性。有关为什么需要此操作的更多信息,请参阅 https://reactjs.ac.cn/learn/rendering-lists必须将
field.id
(而不是index
)添加为组件键,以防止重新渲染破坏字段// ✅ 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 renderReact.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' });
示例
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`)} /><Controllerrender={({ field }) => <input {...field} />}name={`test.${index}.lastName`}control={control}/><button type="button" onClick={() => remove(index)}>Delete</button></li>))}</ul><buttontype="button"onClick={() => append({ firstName: "bill", lastName: "luo" })}>append</button><input type="submit" /></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 (<Controllercontrol={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 在你的项目中很有用,请考虑为其加星并支持它。