使用Yup与React Hook Form时如何配置多套表单校验schema?
Yup 多表单差异化校验配置方案
方案1:拆分独立Schema(最推荐)
将公共字段的校验规则抽离复用,分别为登录、注册表单定义独立的schema,从根源避免无关字段的校验逻辑互相干扰。
代码示例:
// 抽离公共校验规则实现复用 const commonEmailRule = yup.string().email("邮箱格式不正确").required("邮箱不能为空"); const commonPasswordRule = yup.string().min(4, "密码最少4位").max(20, "密码最多20位").required("密码不能为空"); // 登录表单专属校验Schema const loginSchema = yup.object().shape({ email: commonEmailRule, password: commonPasswordRule }); // 注册表单专属校验Schema const registerSchema = yup.object().shape({ email: commonEmailRule, password: commonPasswordRule, userName: yup.string().required("用户名不能为空").min(2, "用户名最少2位"), repeatPassword: yup.string() .required("请确认密码") .oneOf([yup.ref("password")], "两次输入的密码不一致") });
使用时分别给两个表单的useForm注入对应schema即可:
// 登录表单配置 const { control, handleSubmit, formState: { errors } } = useForm<IFormInputs>({ resolver: yupResolver(loginSchema) }); // 注册表单配置 const { control, handleSubmit, formState: { errors } } = useForm<IRegisterFormInputs>({ resolver: yupResolver(registerSchema) });
方案2:单Schema条件校验(适合字段差异极小的场景)
如果需要复用同一个schema,可以通过Yup的when方法,根据表单标识字段动态切换校验规则。
首先需要在表单中新增一个标识字段(可设为隐藏不展示),用来区分当前是登录还是注册场景:
const schema = yup.object().shape({ // 表单类型标识,可选值 login/register formType: yup.string().oneOf(["login", "register"]).required(), email: commonEmailRule, password: commonPasswordRule, // 仅注册场景校验用户名字段 userName: yup.string().when("formType", { is: "register", then: (schema) => schema.required("用户名不能为空").min(2), otherwise: (schema) => schema.notRequired() }), // 仅注册场景校验确认密码字段 repeatPassword: yup.string().when("formType", { is: "register", then: (schema) => schema.required("请确认密码").oneOf([yup.ref("password")], "两次密码输入不一致"), otherwise: (schema) => schema.notRequired() }) });
使用时需要在对应表单的useForm配置中传入对应的formType默认值:
// 登录表单配置 const { control, handleSubmit, formState: { errors } } = useForm<IFormInputs>({ resolver: yupResolver(schema), defaultValues: { formType: "login" } }); // 注册表单配置 const { control, handleSubmit, formState: { errors } } = useForm<IFormInputs>({ resolver: yupResolver(schema), defaultValues: { formType: "register" } });
原问题原因说明
Yup默认会对schema中定义的所有字段执行校验,如果登录表单没有提交userName、repeatPassword字段,schema会将其识别为undefined触发校验报错,因此优先推荐拆分独立schema的方案,逻辑更清晰、维护成本更低。
内容的提问来源于stack exchange,提问作者Peter Boomsma
相关产品推荐
相关产品推荐

