如何正确向Yup校验Schema传递isAdmin上下文参数值
问题根源
你拿不到isAdmin值的核心原因有两个:
- 你通过
useForm传入的context是独立于表单字段的外部上下文,不会自动映射成schema里定义的同名字段值。你在schema里把isAdmin写成普通表单字段,这里读到的永远是表单内注册的isAdmin字段的输入值,和你传的context完全没关系——你既没注册这个字段,也没给它设过值,打出来当然是undefined。 - Yup的
transform方法只有三个入参:当前字段转换后的值、原始输入值、当前schema实例,本身不直接暴露外部传入的上下文,所以你没法在transform里直接拿到传进来的isAdmin。
正确实现方式
首先确认你使用的@hookform/resolvers/yup版本为2.0以上,新版本的yupResolver会自动把useForm配置中传入的context透传给Yup校验层,不需要额外做传参适配。
1. 修正schema写法
不要把外部上下文isAdmin写成普通表单字段,Yup原生支持通过$前缀的key直接引用传入的context值,可以直接在when方法里依赖context做条件校验,示例代码如下:
import { object, string } from 'yup'; export const schema = object().shape( { facility: object().nullable().required('Required!'), // 依赖context里的isAdmin配置paymentMethod校验规则 paymentMethod: object().nullable().when('$isAdmin', { is: true, // 按你的业务需求写管理员身份下的规则,示例为管理员不需要校验必填 then: (schema) => schema.nullable(), otherwise: (schema) => schema.required('Required!'), }), // 同时依赖表单字段paymentMethod和context里的isAdmin做校验 otherPaymentMethod: string().when(['paymentMethod', '$isAdmin'], { is: (paymentMethod, isAdmin) => { // 示例规则:非管理员且支付方式选择“其他”时,该字段必填 return !isAdmin && paymentMethod?.value === '-1'; }, then: string().nullable().required('Required'), otherwise: string().nullable() }), }, );
2. useForm配置无需大改
你原来的useForm传参写法是正确的,context会自动透传,如果需要动态修改isAdmin,可以解构出updateContext方法使用:
const { handleSubmit, control, setValue, updateContext, // 动态更新上下文用这个方法 formState: { errors }, } = useForm({ context: { isAdmin: true }, resolver: yupResolver(schema), mode: 'onBlur', });
如果后续需要动态切换isAdmin状态(比如用户切换身份),不要直接修改传入的context对象,调用updateContext({ isAdmin: false })即可更新上下文并自动触发表单重新校验。
补充:如果一定要在transform中获取context
transform本身不直接支持读取context,你可以通过test自定义校验方法拿到context后做值转换,或者把schema改成工厂函数接收外部参数传入,不过对于条件校验场景,直接用上述$前缀引用context的官方写法是最简洁、兼容性最好的方案。
内容的提问来源于stack exchange,提问作者Sweet Caramel
相关产品推荐
相关产品推荐

