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

Vite+TS注册页中Yup的Avatar必填验证未显示问题求助

问题:头像未选择时未触发必填验证,直接显示文件类型错误

使用Vite+TypeScript开发注册页面,采用react-hook-form处理表单、Yup做验证。表单包含username、fullname、email、password和avatar(头像文件)5个字段。为所有字段设置了必填规则,但未选择头像时,未触发“Avatar is required”提示,反而直接显示文件类型无效的错误。


相关代码

验证Schema代码

const validFileExtensions = ["jpg", "jpeg", "png", "gif", "svg", "webp"];

function isValidFileType(fileName?: string): boolean {
  if (!fileName) return false;
  const extension = fileName.split(".").pop()?.toLowerCase();
  return extension ? validFileExtensions.includes(extension) : false;
}

// validation schema with yup
const validationSchema = Yup.object().shape({
  email: Yup.string().required("Email is required").email("Email is invalid"),
  password: Yup.string()
    .required("Password is required")
    .min(8, "Password must be at least 8 characters long"),
  fullname: Yup.string().required("Full name is required"),
  username: Yup.string()
    .required("Username is required")
    .min(4, "At least 4 characters ")
    .matches(/^\S+$/, "No spaces allowed"),
  avatar: Yup.mixed<File>()
    .required("Avatar is required")
    .test(
      "fileType",
      "Only JPG, JPEG, PNG, GIF, SVG, and WEBP files are allowed",
      (value) => {
        if (!value) return true;
        return isValidFileType(value.name);
      }
    )
    .test("fileSize", "File must be less than 100KB", (value) => {
      if (!value) return true;
      return value.size <= MAX_FILE_SIZE;
    }),

  // --- 注释的旧测试逻辑 ---
  // .test("fileType", "Unsupported file format", (value) => {
  //   if (!value || value.length === 0) return false;
  //   const file = value[0];
  //   return ["image/jpeg", "image/png"].includes(file.type);
  // })
  // .test("fileSize", "File must be less than 2MB", (value) => {
  //   if (!value || value.length === 0) return false;
  //   const file = value[0];
  //   return file.size <= 2 * 1024 * 1024;
  // }), ---
});

react-hook-form初始化代码

const {
  register,
  handleSubmit,
  formState: { errors },
} = useForm<SignUpFormInputs>({
  resolver: yupResolver(validationSchema),
});

传递错误给UploadFileInput组件代码

<UploadFileInput
  label="Upload an Avatar"
  id="uploadAvatar"
  name="avatar"
  errors={errors.avatar?.message}
  register={register}
/>

UploadFileInput组件代码

import React from "react";
import { UseFormRegister } from "react-hook-form";
import { RxAvatar } from "react-icons/rx";

interface SignUpFormInputs {
  email: string;
  password: string;
  fullname: string;
  username: string;
  avatar: File;
}

interface UploadFileInputProps {
  id: string;
  label: string;
  name: keyof SignUpFormInputs;
  errors?: string;
  register: UseFormRegister<SignUpFormInputs>;
}

const UploadFileInput: React.FC<UploadFileInputProps> = ({
  id,
  label,
  name,
  register,
  errors,
}) => {
  return (
    <>
      <label
        className="text-[17px]  w-[50%] text-center text-gray-400  text-sm bg-gray-100 file:cursor-pointer p-2 cursor-pointer    file:text-white"
        htmlFor={id}
      >
        <span className=" flex items-center gap-2">
          <RxAvatar size={30} />
          {label}
        </span>
        <input id={id} type="file" className="hidden" {...register(name)} />
        {errors && (
          <p className="absolute  ml-[-9px] text-red-500 text-sm mt-3 ">
            {errors}
          </p>
        )}
      </label>
    </>
  );
};

export default UploadFileInput;

问题截图

问题截图


解决方案

核心问题是react-hook-form默认会将文件输入的值解析为字符串(而非File对象),导致Yup的required规则和自定义测试逻辑出现异常。按以下步骤修复:

1. 注册文件输入时启用valueAsFile

修改UploadFileInput组件中的文件输入注册逻辑,让react-hook-form将值解析为File对象:

<input 
  id={id} 
  type="file" 
  className="hidden" 
  {...register(name, { valueAsFile: true })} 
/>

2. 修正类型定义

将SignUpFormInputs中的avatar改为可选类型,匹配未选择文件时的undefined值:

interface SignUpFormInputs {
  email: string;
  password: string;
  fullname: string;
  username: string;
  avatar?: File; // 改为可选类型
}

3. 保留现有Yup验证逻辑

你的Yup规则已经正确:required会在值为undefined时触发必填错误,自定义测试仅在文件存在时执行类型/大小验证,不会干扰必填规则。

调整后,未选择头像时会正常显示“Avatar is required”提示,选择文件后才会执行后续的文件格式和大小验证。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 14:08:16