You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 09:35:10