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

Yup的notRequired在单选框与URL字段上失效问题

表单验证问题:Radio非必填字段仍强制校验的解决方案

问题背景

使用React-Bootstrap、React-Hook-Form和Yup构建表单,其中offerInternships、offerVisaSponsorship、offerRemoteWork三个Radio字段已在Yup Schema中标记为notRequired(),但提交表单时仍被提示必须填写;URL字段已通过在正则末尾添加|^$解决空值校验问题,但Radio字段的问题依旧存在。

问题原因

  1. 默认值未同步到表单状态:Yup的default(false)不会自动同步到React-Hook-Form的表单状态中,用户未选择Radio选项时,字段值为undefined,触发Yup隐性类型校验。
  2. 类型不匹配:Radio组件的value属性设置为字符串"true"/"false",但Yup Schema中定义的是bool类型,类型不匹配导致校验失败,即使标记为非必填也会报错。

修复步骤

1. 为React-Hook-Form设置默认值

在useForm配置中添加defaultValues,确保Radio字段初始值为布尔类型的false:

const {
  register,
  handleSubmit,
  watch,
  formState: { errors },
} = useForm({
  resolver: yupResolver(formSchema),
  mode: "all",
  defaultValues: { // 添加默认值配置
    offerInternships: false,
    offerRemoteWork: false,
    offerVisaSponsorship: false,
  }
});

2. 调整Yup Schema的类型校验

将Radio字段的类型从yup.bool()改为yup.mixed(),允许接受字符串并转换为布尔值,同时保留非必填和默认值设置:

const formSchema = yup.object().shape({
  // ...其他字段保持不变
  offerInternships: yup.mixed().oneOf([true, false, 'true', 'false'])
    .transform(val => val === 'true' || val === true)
    .default(false)
    .notRequired(),
  offerRemoteWork: yup.mixed().oneOf([true, false, 'true', 'false'])
    .transform(val => val === 'true' || val === true)
    .default(false)
    .notRequired(),
  offerVisaSponsorship: yup.mixed().oneOf([true, false, 'true', 'false'])
    .transform(val => val === 'true' || val === true)
    .default(false)
    .notRequired(),
  // ...其他字段保持不变
});

3. 移除Register中的冗余配置

删除Radio组件register中的{ required: false },因为已在Yup Schema中定义非必填,重复设置可能导致冲突:

// 原代码
<Form.Check
  inline
  label="Yes"
  value="true"
  {...register("offerInternships", { required: false })}
  type="radio"
  isInvalid={!!errors.offerInternships}
/>

// 修改后
<Form.Check
  inline
  label="Yes"
  value="true"
  {...register("offerInternships")}
  type="radio"
  isInvalid={!!errors.offerInternships}
/>

修改后的完整代码

import { Container, Row, Col, Button, Form } from "react-bootstrap";
import * as yup from "yup";
import { useForm } from "react-hook-form";
import { yupResolver } from "@hookform/resolvers/yup";

/**
 * Company's validation schema.
 */
const re =
  /^((ftp|http|https):\/\/)?(www.)?(?!.*(ftp|http|https|www.))[a-zA-Z0-9_-]+(\.[a-zA-Z]+)+((\/)[\w#]+)*(\/\w+\?[a-zA-Z0-9_]+=\w+(&[a-zA-Z0-9_]+=\w+)*)?$|^$/gm;
const formSchema = yup.object().shape({
  url: yup.string().matches(re, "Enter a valid URL!").required(),
  name: yup.string().required(),
  location: yup.object().shape({
    country: yup.string().required(),
    state: yup.string().required(),
    city: yup.string().required(),
    address: yup.string().required(),
  }),
  offerInternships: yup.mixed().oneOf([true, false, 'true', 'false'])
    .transform(val => val === 'true' || val === true)
    .default(false)
    .notRequired(),
  offerRemoteWork: yup.mixed().oneOf([true, false, 'true', 'false'])
    .transform(val => val === 'true' || val === true)
    .default(false)
    .notRequired(),
  offerVisaSponsorship: yup.mixed().oneOf([true, false, 'true', 'false'])
    .transform(val => val === 'true' || val === true)
    .default(false)
    .notRequired(),
  socialMedia: yup.object().shape({
    Linkedin: yup.string().matches(re, "Enter a valid URL!").notRequired(),
    GitHub: yup.string().matches(re, "Enter a valid URL!").notRequired(),
  }),
});
const RequestForm = () => {
  const {
    register,
    handleSubmit,
    watch,
    formState: { errors },
  } = useForm({
    resolver: yupResolver(formSchema),
    mode: "all",
    defaultValues: {
      offerInternships: false,
      offerRemoteWork: false,
      offerVisaSponsorship: false,
    }
  });

  /**
   * Handling the submittion of the form
   */
  const onSubmit = async (data) => {
    try {
      console.log(errors);
      console.log(data);
    } catch (error) {
      console.log(error);
    }
  };
  return (
    <>
      <Container id="RequestForm-UserForm" className="mt-5 outer-border p-5">
        <Form onSubmit={handleSubmit(onSubmit)}>
          <Row id="company-details-row">
            <Col id="company-details-row-input" sm={12} md={9}>
              <Form.Group className="mb-2" controlId="formBasicEmail">
                <Form.Label>Company's name</Form.Label>
                <Form.Control
                  type="text"
                  placeholder="e.g. Microsoft"
                  {...register("name")}
                  isInvalid={!!errors?.name}
                />
              </Form.Group>
              <Form.Group className="mb-2" controlId="formBasicEmail">
                <Form.Label>Company's website</Form.Label>
                <Form.Control
                  type="text"
                  placeholder="e.g. https://www.microsoft.com"
                  {...register("url")}
                  isInvalid={!!errors.url}
                />
              </Form.Group>
              <h3 className="mb-0">Location</h3>
              <Form.Group className="mb-2" controlId="formBasicEmail">
                <Form.Label>Country</Form.Label>
                <Form.Control
                  type="text"
                  placeholder="e.g. Egypt, United States of America,...etc."
                  {...register("location.country")}
                  isInvalid={!!errors.location?.country}
                />
              </Form.Group>
              <Form.Group className="mb-2" controlId="formBasicEmail">
                <Form.Label>State/Governorate</Form.Label>
                <Form.Control
                  type="text"
                  placeholder="e.g. Cairo, California, Berlin...etc."
                  {...register("location.state")}
                  isInvalid={!!errors.location?.state}
                />
              </Form.Group>
              <Form.Group className="mb-2" controlId="formBasicEmail">
                <Form.Label>City</Form.Label>
                <Form.Control
                  type="text"
                  placeholder="e.g. Maadi, San Francisco,...etc."
                  {...register("location.city")}
                  isInvalid={!!errors.location?.city}
                />
              </Form.Group>
              <Form.Group className="mb-2" controlId="formBasicEmail">
                <Form.Label>Address</Form.Label>
                <Form.Control
                  type="text"
                  placeholder="e.g. 14th Zaki Sayed St."
                  {...register("location.address")}
                  isInvalid={!!errors.location?.address}
                />
              </Form.Group>
              <h3 className="mt-2 mb-0">Social Media</h3>
              <Form.Group className="mb-2" controlId="formBasicEmail">
                <Form.Label>
                  <i className="icon ion-social-linkedin"></i> Linkedin
                </Form.Label>
                <Form.Control
                  type="text"
                  placeholder="e.g. https://www.linkedin.com/company/x"
                  {...register("socialMedia.Linkedin")}
                  isInvalid={!!errors.socialMedia?.Linkedin}
                />
              </Form.Group>
              <Form.Group className="mb-2" controlId="formBasicEmail">
                <Form.Label>
                  <i className="icon ion-social-github"></i> GitHub
                </Form.Label>
                <Form.Control
                  type="text"
                  placeholder="e.g. https://www.github.com/company"
                  {...register("socialMedia.GitHub")}
                  isInvalid={!!errors.socialMedia?.GitHub}
                />
              </Form.Group>
              <h3 className="mt-2 mb-0">Culture & Environment</h3>
              <div id="offer-Internship" key="inline-radio-internships">
                <Form.Label>Does your company offer internships? 🎓</Form.Label>
                <br></br>
                <Form.Check
                  inline
                  label="Yes"
                  value="true"
                  {...register("offerInternships")}
                  type="radio"
                  isInvalid={!!errors.offerInternships}
                />
                <Form.Check
                  inline
                  label="No"
                  value="false"
                  {...register("offerInternships")}
                  type="radio"
                  isInvalid={!!errors.offerInternships}
                />
              </div>
              <div id="offer-VisaSponsorship" key="inline-radio-visa">
                <Form.Label>
                  Does your company offer visa sponsorship? ✈️
                </Form.Label>
                <br></br>
                <Form.Check
                  inline
                  label="Yes"
                  value="true"
                  {...register("offerVisaSponsorship")}
                  type="radio"
                  isInvalid={!!errors.offerVisaSponsorship}
                />
                <Form.Check
                  {...register("offerVisaSponsorship")}
                  inline
                  label="No"
                  value="false"
                  type="radio"
                  isInvalid={!!errors.offerVisaSponsorship}
                />
              </div>
              <div id="offer-remoteWork" key="inline-radio-remote">
                <Form.Label>
                  Does your company offer remote working? 🗺️
                </Form.Label>
                <br></br>
                <Form.Check
                  {...register("offerRemoteWork")}
                  inline
                  label="Yes"
                  value="true"
                  type="radio"
                  isInvalid={!!errors.offerRemoteWork}
                />
                <Form.Check
                  {...register("offerRemoteWork")}
                  inline
                  label="No"
                  value="false"
                  type="radio"
                  isInvalid={!!errors.offerRemoteWork}
                />
              </div>
            </Col>
          </Row>
          <Row id="company-submit text-center">
            <Col className="text-center" sm={12}>
              <h2 className="fs-1 main-color-1-dark">
                We have reached to the end of the form! 🎆
              </h2>
              <Button variant="success" type="submit" className="rubik-font">
                Submit form
              </Button>
            </Col>
          </Row>
        </Form>
      </Container>
    </>
  );
};
export default RequestForm;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 09:21:35