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

React-Hook-Form+Yup Resolver3.1.1:允许null初始值但提交需对象

React-Hook-Form + React-Select + Yup Resolver 3.1.1 校验失效问题

在TS NextJS13项目中,使用React-Hook-Form的Controller结合React-Select组件,搭配Yup Resolver做表单校验时遇到以下问题:

  • React Hook Form不允许Controller的默认值为undefined,因此将默认值设为null
  • 升级到Yup Resolver 3.1.1后,要求以Schema作为表单类型推导依据,必须给Select对应的Yup Schema添加.nullable()才能兼容null默认值
  • 但添加.nullable()后,表单允许在未选择有效{value:string, label:string}类型对象的情况下提交,破坏了必填校验逻辑

3.1.0版本可用代码示例

import * as yup from 'yup';
import { useForm, Controller } from 'react-hook-form';
import { yupResolver } from '@hookform/resolvers/yup';
import Select from 'react-select';

// 定义选项类型
interface SelectOptionType {
  label: string;
  value: string;
}

// 定义表单类型
interface InputType {
  category: SelectOptionType | null;
}

// Yup校验规则
const schema = yup.object().shape({
  category: yup
    .object()
    .shape({
      label: yup.string().required("Tag is required"),
      value: yup.string().required("Tag is required"),
    })
    .required()
});

// 初始化表单
const { control, handleSubmit } = useForm<InputType>({
  resolver: yupResolver(schema),
  defaultValues: {
    category: null,
  }
});

3.1.1版本的问题

3.1.1版本要求移除手动定义的InputType,由Yup Schema自动推导表单类型。但直接给Schema添加.nullable()后,校验逻辑失效,允许category为null时提交表单。同时当前Yup版本不再支持.nullable(true)的写法。

解决方案

通过.nullable().required()的组合,既兼容null默认值,又确保提交时必须传入有效对象:

import * as yup from 'yup';
import { useForm, Controller } from 'react-hook-form';
import { yupResolver } from '@hookform/resolvers/yup';
import Select from 'react-select';

// Yup校验规则:先允许null,再强制要求提交时为有效对象
const schema = yup.object().shape({
  category: yup
    .object({
      label: yup.string().required("Tag is required"),
      value: yup.string().required("Tag is required"),
    })
    .nullable()
    .required("Please select a category") // 阻止提交时为null
});

// 表单初始化:无需手动传泛型,由Schema自动推导
const { control, handleSubmit } = useForm({
  resolver: yupResolver(schema),
  defaultValues: {
    category: null,
  }
});

// Controller使用示例
<Controller
  name="category"
  control={control}
  render={({ field, fieldState: { error } }) => (
    <Select
      {...field}
      options={yourOptions}
      isClearable
      placeholder="Select category"
      error={!!error}
      helperText={error?.message}
    />
  )}
/>

如果上述组合无法满足需求(如部分Yup版本中nullable后required逻辑异常),可使用自定义校验规则:

const schema = yup.object().shape({
  category: yup
    .mixed()
    .nullable()
    .test(
      'valid-category',
      'Please select a valid category with label and value',
      (value) => {
        if (value === null) return false; // 不允许提交时为null
        // 校验对象结构
        return yup.object({
          label: yup.string().required(),
          value: yup.string().required(),
        }).isValidSync(value);
      }
    )
});

内容的提问来源于stack exchange,提问作者Ivomasterche

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 23:53:11