React Hook Form是React生态中广受欢迎的表单管理库,凭借轻量、高性能、低重渲染的特性,成为很多项目的表单首选方案。在处理动态表单场景时,它提供了专门的API支持,能够轻松实现表单项的动态增删、不定数量数据的管理以及相关逻辑处理。

核心API:useFieldArray
React Hook Form中处理动态表单的核心API是useFieldArray,它可以管理数组类型的表单字段,支持动态添加、删除、插入、替换数组项,同时自动处理每个字段的注册、校验和值更新。
使用useFieldArray前需要先通过useForm创建表单实例,再传入control对象、字段名称等参数初始化动态字段数组。以下是基础的使用结构:
import { useForm, useFieldArray } from "react-hook-form";
function DynamicForm() {
// 创建表单实例
const { control, handleSubmit, register } = useForm({
defaultValues: {
// 动态字段的默认初始值,这里初始化为空数组
items: []
}
});
// 初始化动态字段数组
const { fields, append, remove, insert } = useFieldArray({
control,
name: "items" // 对应表单数据中的字段名
});
// 表单提交处理函数
const onSubmit = (data) => {
console.log("表单提交数据:", data);
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
{/* 动态表单项渲染区域 */}
<ul>
{fields.map((field, index) => (
<li key={field.id}>
{/* 每个动态项的输入框 */}
<input
{...register(`items.${index}.value`)}
placeholder={`请输入第${index + 1}项内容`}
/>
{/* 删除当前项按钮 */}
<button type="button" onClick={() => remove(index)}>
删除
</button>
</li>
))}
</ul>
{/* 添加新表单项按钮 */}
<button type="button" onClick={() => append({ value: "" })}>
添加新项
</button>
{/* 提交按钮 */}
<button type="submit">提交</button>
</form>
);
}
动态表单数据校验
动态表单的校验规则和普通表单类似,只需要在register的时候传入校验配置即可,React Hook Form会自动对每个动态字段应用校验规则。
比如需要限制每个动态输入项不能为空,且长度不超过20个字符,可以修改上面的register配置:
<input
{...register(`items.${index}.value`, {
required: "该项不能为空",
maxLength: {
value: 20,
message: "内容不能超过20个字符"
}
})}
placeholder={`请输入第${index + 1}项内容`}
/>
如果需要展示校验错误信息,可以结合formState.errors获取对应字段的错误:
// 获取表单错误信息
const { errors } = formState;
// 在动态项渲染时展示错误
{fields.map((field, index) => (
<li key={field.id}>
<input
{...register(`items.${index}.value`, {
required: "该项不能为空"
})}
/>
{/* 展示当前项的错误信息 */}
{errors.items?.[index]?.value && (
<span style={{ color: "red" }}>
{errors.items[index].value.message}
</span>
)}
<button type="button" onClick={() => remove(index)}>删除</button>
</li>
))}
动态表单数据提交与重置
动态表单的提交数据会自动按照useFieldArray的name配置生成对应的数组结构,比如上面的示例中,提交的数据格式为{ items: [{value: "第一项内容"}, {value: "第二项内容"}] },可以直接对接后端接口。
如果需要重置动态表单,可以使用表单实例的reset方法,重置时可以指定新的默认值,也可以清空所有动态项:
// 重置表单为初始空状态
const handleReset = () => {
reset({
items: []
});
};
// 在表单中添加重置按钮
<button type="button" onClick={handleReset}>重置表单</button>
常见场景示例:动态联系人表单
实际开发中经常会遇到需要动态添加联系人的场景,每个联系人包含姓名、电话两个字段,以下是完整实现示例:
import { useForm, useFieldArray } from "react-hook-form";
function ContactForm() {
const { control, handleSubmit, register, formState: { errors } } = useForm({
defaultValues: {
contacts: [{ name: "", phone: "" }]
}
});
const { fields, append, remove } = useFieldArray({
control,
name: "contacts"
});
const onSubmit = (data) => {
console.log("联系人数据:", data.contacts);
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
<h3>动态联系人表单</h3>
{fields.map((field, index) => (
<div key={field.id} style={{ marginBottom: "10px", border: "1px solid #ccc", padding: "10px" }}>
<div>
<label>姓名:</label>
<input
{...register(`contacts.${index}.name`, {
required: "姓名不能为空"
})}
/>
{errors.contacts?.[index]?.name && (
<span style={{ color: "red" }}>{errors.contacts[index].name.message}</span>
)}
</div>
<div>
<label>电话:</label>
<input
{...register(`contacts.${index}.phone`, {
required: "电话不能为空",
pattern: {
value: /^1[3-9]d{9}$/,
message: "请输入正确的手机号"
}
})}
/>
{errors.contacts?.[index]?.phone && (
<span style={{ color: "red" }}>{errors.contacts[index].phone.message}</span>
)}
</div>
{fields.length > 1 && (
<button type="button" onClick={() => remove(index)}>
删除该联系人
</button>
)}
</div>
))}
<button type="button" onClick={() => append({ name: "", phone: "" })}>
添加联系人
</button>
<button type="submit">提交</button>
</form>
);
}
注意事项
- 动态字段的
key要使用useFieldArray返回的field.id,不要使用数组的index作为key,避免删除项时出现渲染异常。 - 如果动态字段需要自定义组件,需要将
control传递给自定义组件,在组件内部通过useController或者register注册字段。 - 动态表单的性能优化:如果动态项数量很多,可以结合
React.memo包裹单个动态项组件,减少不必要的重渲染。
React_Hook_Form动态表单表单数据处理useFieldArray修改时间:2026-07-06 10:54:32