如何在Yup+React Hook Form中联动校验字段,同步更新错误提示?
问题场景与解决方案
问题描述
需求是firstname和lastname字段不能同时为空:
- 两个字段都为空时,显示错误提示;
- 任一字段不为空时,不显示错误。
使用Yup结合React Hook Form实现后,出现以下问题:
- 两个字段都为空时,错误提示正常显示;
- 修改其中一个字段的值后,另一个字段的错误提示依然存在,必须手动触发该输入框的blur事件,错误才会消失。
原因分析
React Hook Form默认仅在字段被交互(如输入、失去焦点)或表单提交时触发校验。当修改其中一个字段时,另一个未被交互的字段不会自动重新校验,导致旧的错误提示残留。
解决方法
通过watch监听两个字段的变化,当任一字段值改变时,手动调用trigger方法触发另一个字段的校验,确保错误提示实时更新。
修改后的代码示例
import { useForm, useEffect } from "react-hook-form"; import { yupResolver } from "@hookform/resolvers/yup"; import * as yup from "yup"; const schema = yup.object().shape({ firstname: yup.string().test({ name: "not-both-empty", message: "至少填写姓名或姓氏其中一项", test: function (value) { const { lastname } = this.parent; return value || lastname; }, }), lastname: yup.string().test({ name: "not-both-empty", message: "至少填写姓名或姓氏其中一项", test: function (value) { const { firstname } = this.parent; return value || firstname; }, }), }); export default function App() { const { register, formState: { errors }, watch, trigger, } = useForm({ resolver: yupResolver(schema), mode: "onTouched", }); // 实时监听两个字段的值 const [firstname, lastname] = watch(["firstname", "lastname"]); // 任一字段变化时,触发另一个字段的校验 useEffect(() => { if (firstname) { trigger("lastname"); } if (lastname) { trigger("firstname"); } }, [firstname, lastname, trigger]); return ( <div className="App"> <div> <label>Firstname:</label> <input {...register("firstname")} /> {errors.firstname && <p>{errors.firstname.message}</p>} </div> <div> <label>Lastname:</label> <input {...register("lastname")} /> {errors.lastname && <p>{errors.lastname.message}</p>} </div> </div> ); }
说明
- 用
watch监听firstname和lastname的实时值,当其中一个字段有内容时,调用trigger触发另一个字段的校验; - 保留了原有的
mode: "onTouched"模式,避免输入过程中频繁触发校验,同时保证错误提示能及时更新; - 也可以根据需求将表单模式改为
"onChange",但这种方式会在用户每一次输入时都触发所有字段校验,灵活性不如前者。
内容的提问来源于stack exchange,提问作者jianbo
相关产品推荐
相关产品推荐

