如何实现react-hook-form的动态Resolver验证?
动态切换react-hook-form的Yup验证规则
我使用react-hook-form处理表单提交,需要实现以下动态验证逻辑:表单的category字段有三个选项:'firstCategory'、'secondCategory'、'thirdCategory'。当选中'firstCategory'时,version字段需变为必填项(验证规则从Yup.string().nullable()改为Yup.string().nullable().required('Version is required'));选择另外两个选项时,version无需必填验证。
原有代码如下:
const Schema = Yup.object().shape({ category: Yup.string().nullable().required('Category is required'), title: Yup.string().nullable().required('Title is required'), version: Yup.string().nullable() }); const DynamicSchema = Yup.object().shape({ category: Yup.string().nullable().required('Category is required'), title: Yup.string().nullable().required('Title is required'), version: Yup.string().nullable().required('Version is required') }); const methods = useForm({ resolver: yupResolver(Schema), defaultValues, }); const { getValues, setValue, watch, handleSubmit, formState: { isSubmitting }, } = methods; ... return ( <FormProvider methods={methods} onSubmit={handleSubmit(onSubmit)}> <RHFSelect name="category" label="Category"> {CATEGORY.map((item) => ( <MenuItem > {item.label} </MenuItem> ))} </RHFSelect> {watch('category') === 'firstCategory' && ( <RHFTextField name="version" label="Version" /> )}
我尝试过动态切换resolver,但此时watch方法尚未定义,无法实现:
resolver: yupResolver(Schema), // resolver: watch('category') === 'firstCategory' ? yupResolver(Schema) : yupResolver(DynamicSchema) defaultValues, });
有没有办法实现resolver的动态切换?
解决方案:用Yup的when方法实现动态验证
不需要动态切换resolver,直接利用Yup内置的when方法,就能根据category的字段值动态设置version的验证规则,这是更简洁且符合Yup设计逻辑的方案。
修改后的代码如下:
import { Controller, useForm } from 'react-hook-form'; const Schema = Yup.object().shape({ category: Yup.string().nullable().required('Category is required'), title: Yup.string().nullable().required('Title is required'), version: Yup.string().when('category', (categoryValue) => { // 匹配实际选项值,与表单传入的value保持一致 if (categoryValue === 'firstCategory') { return Yup.string().nullable().required('Version is required'); } else { return Yup.string().nullable(); } }), }); const { getValues, setValue, watch, handleSubmit, control, formState: { isSubmitting, errors }, } = useForm({ resolver: yupResolver(Schema), defaultValues, }); ... return ( <FormProvider onSubmit={handleSubmit(onSubmit)}> <FormControl> <Controller name="category" control={control} render={({ field }) => ( <RHFSelect {...field} label={<EssentialLabel text="Category" />} > {CATEGORY_LIST.map((item) => ( <MenuItem key={item.code} value={item.code} onClick={() => field.onChange(item.code) // 传递字符串类型的value,与字段定义匹配 }> {item.label} </MenuItem> ))} </RHFSelect> )} /> </FormControl> {/* 可保留条件渲染隐藏字段,同时添加错误提示 */} {watch('category') === 'firstCategory' && ( <RHFTextField name="version" label="Version" error={!!errors.version} helperText={errors.version?.message} /> )} </FormProvider> )
注意事项:
Yup.when回调接收的是category的当前值,要确保和表单中实际传入的value类型一致(比如把onChange(item)改为onChange(item.code),因为category字段定义为字符串类型)。- 如果保留
version的条件渲染,建议在字段隐藏时手动重置值,避免提交无效数据。
内容的提问来源于stack exchange,提问作者user22285151
相关产品推荐
相关产品推荐

