React-Hook-Form中useFieldArray添加元素时验证前序数组项的需求
解决React-Hook-Form中useFieldArray添加新字段前校验前序项的问题
核心思路
在调用append添加新数组项之前,手动触发已有数组项的字段校验,通过trigger方法指定需要校验的字段路径,校验全部通过后再执行添加操作。React-Hook-Form的trigger会自动更新表单错误状态,错误信息会直接绑定到对应字段的错误提示组件上。
具体实现代码
import { useForm, useFieldArray } from "react-hook-form"; type FormValues = { items: { name: string; email: string; }[]; }; export default function DynamicForm() { const { register, control, trigger, formState: { errors } } = useForm<FormValues>({ defaultValues: { items: [{ name: "", email: "" }] } }); const { fields, append } = useFieldArray({ control, name: "items" }); const handleAddItem = async () => { // 收集所有已有数组项的字段路径,批量触发校验 const fieldPaths = fields.flatMap((_, index) => [ `items.${index}.name`, `items.${index}.email` ]); // 触发校验,返回布尔值表示是否全部通过 const isValid = await trigger(fieldPaths); if (isValid) { // 校验通过,添加新的空项 append({ name: "", email: "" }); } // 校验不通过时,errors会自动更新,对应字段的错误提示会显示 }; return ( <form> {fields.map((item, index) => ( <div key={item.id} style={{ marginBottom: "1rem" }}> <div> <label>姓名</label> <input {...register(`items.${index}.name`, { required: "姓名不能为空", minLength: { value: 2, message: "姓名至少2个字符" } })} placeholder="请输入姓名" /> {errors.items?.[index]?.name && ( <span style={{ color: "red" }}>{errors.items[index].name.message}</span> )} </div> <div> <label>邮箱</label> <input {...register(`items.${index}.email`, { required: "邮箱不能为空", pattern: { value: /^[^\s@]+@[^\s@]+\.[^\s@]+$/, message: "请输入合法邮箱" } })} placeholder="请输入邮箱" /> {errors.items?.[index]?.email && ( <span style={{ color: "red" }}>{errors.items[index].email.message}</span> )} </div> </div> ))} <button type="button" onClick={handleAddItem}>添加新项</button> </form> ); }
关键细节说明
- 批量校验字段:通过
fields.flatMap生成所有已有数组项的完整字段路径(比如items.0.name、items.0.email),传给trigger实现批量校验。 - 校验结果判断:
trigger返回Promise,resolve为布尔值,true表示所有指定字段校验通过,此时才执行append。 - 错误自动展示:只要触发了校验,React-Hook-Form会自动更新
errors对象,对应索引的字段错误提示会根据errors.items?.[index]?.字段名的存在性显示。
可选优化:仅校验最后一个前序项
如果只需要校验最后一个已存在的数组项(而非全部),可以修改handleAddItem:
const handleAddItem = async () => { if (fields.length === 0) { append({ name: "", email: "" }); return; } const lastIndex = fields.length - 1; const fieldPaths = [ `items.${lastIndex}.name`, `items.${lastIndex}.email` ]; const isValid = await trigger(fieldPaths); if (isValid) { append({ name: "", email: "" }); } };
内容的提问来源于stack exchange,提问作者sabbir 07
相关产品推荐
相关产品推荐

