Yup 表单验证中如何动态设置必填字段?

程序员玲玲 阅读 10

我在用 React Hook Form 配合 Yup 做表单验证,现在有个需求:当用户勾选“需要发票”时,发票抬头字段才变成必填。但我发现即使 Yup 的 schema 动态变了,表单也不会重新校验这个字段,已经填过的值不会触发错误,没填的也不报错,这是为啥?

我试过用 useEffect 重新生成 schema 并传给 useForm 的 resolver,但好像没生效。代码大概这样:

const schema = yup.object({
  needInvoice: yup.boolean(),
  invoiceTitle: yup.string().when('needInvoice', {
    is: true,
    then: (schema) => schema.required('发票抬头不能为空'),
    otherwise: (schema) => schema.optional(),
  }),
});

const { register, handleSubmit, formState: { errors } } = useForm({
  resolver: yupResolver(schema),
});
我来解答 赞 3 收藏
二维码
手机扫码查看
1 条解答
ლ东江
ლ东江 Lv1
问题在于 Yup 的 .when()本身是响应式的,不需要你重新创建 schema。真正的问题是 RHF 不会在依赖字段(needInvoice)变化时自动触发被依赖字段(invoiceTitle)的重新验证。

解决方案很简单,在 needInvoice 变化时手动触发验证就行:

const { register, handleSubmit, formState: { errors }, trigger } = useForm({
resolver: yupResolver(schema),
});

// 在你的 Checkbox onChange 里
const handleInvoiceChange = async (e) => {
// 先让 register 的 onChange 执行
// ...你的逻辑

// 然后手动触发 invoiceTitle 的验证
if (e.target.checked) {
await trigger('invoiceTitle');
}
};

return (
<input
type="checkbox"
{...register('needInvoice', {
onChange: handleInvoiceChange
})}
/>
);


或者用 watch 监听:

const needInvoice = watch('needInvoice');

useEffect(() => {
if (needInvoice) {
trigger('invoiceTitle');
}
}, [needInvoice, trigger]);


这样当用户勾选需要发票时,就会立刻校验发票抬头字段,没填的话就会报错。

另外提醒一下,你的 otherwise.optional() 是对的,但有些版本可能需要写成 .notRequired(),看具体用的 Yup 版本。
点赞 1
2026-03-11 12:01