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

React表单中使用Yup进行图片字段验证失效问题求助

解决React表单图片字段Yup验证失效问题

问题根源

  • 当前handleChange里把图片转成了URL.createObjectURL()生成的字符串,丢失了原始文件的类型信息,导致Yup无法校验真实文件格式
  • 原有的Yup规则仅验证字段必填,未针对图片格式做校验

修复步骤

1. 保存原始文件对象

修改handleChange,同时存储原始文件对象和预览URL(如需预览):

const handleChange = (e) => {
  if (e.target.type === "file") {
    const file = e.target.files[0];
    setTouristPlace((prev) => ({
      ...prev,
      picture: file, // 保存原始文件对象
      picturePreview: file ? URL.createObjectURL(file) : null // 单独存储预览地址
    }));
  } else {
    const { name, value } = e.target;
    setTouristPlace((prevPlace) => ({
      ...prevPlace,
      [name]: value,
    }));
  }
};

同步更新初始state和重置函数的picture字段:

// 初始state
const [touristPlace, setTouristPlace] = useState(
  place || {
    name: "",
    address: "",
    rating: "",
    type: "",
    picture: null,
    picturePreview: null,
    idx: uuidv4(),
  }
);

// 重置函数
const handleReset = () => {
  setTouristPlace({
    name: "",
    address: "",
    rating: "",
    type: "",
    picture: null,
    picturePreview: null,
    idx: uuidv4(),
  });
  setErrorLog({});
};

2. 编写Yup自定义验证规则

修改validationSchema,针对picture字段(现在是File对象)做必填和格式校验:

const validationSchema = Yup.object().shape({
  name: Yup.string().required("Name of the place is required."),
  address: Yup.string().required("Address of the place is required."),
  rating: Yup.number()
    .required("Must have to be a number between 1 to 5")
    .positive()
    .min(1)
    .max(5),
  picture: Yup.mixed()
    .required("Please select an image file.")
    .test(
      "fileFormat",
      "Only JPEG, PNG, and GIF files are allowed.",
      (value) => {
        if (!value) return true; // 已通过required校验,处理空值兜底
        const allowedFormats = ["image/jpeg", "image/png", "image/gif"];
        return allowedFormats.includes(value.type);
      }
    ),
});

3. 调整预览逻辑(可选)

若需展示图片预览,在JSX中使用picturePreview:

{touristPlace.picturePreview && (
  <img src={touristPlace.picturePreview} alt="Preview" style={{maxWidth: '200px', marginTop: '10px'}} />
)}

4. 额外优化:避免内存泄漏

组件卸载时释放Object URL:

import { useEffect } from "react";

// 在组件内部添加
useEffect(() => {
  return () => {
    if (touristPlace.picturePreview) {
      URL.revokeObjectURL(touristPlace.picturePreview);
    }
  };
}, [touristPlace.picturePreview]);

注意事项

  • 表单的accept属性仅为前端限制,用户仍可上传其他格式文件,后端需同步做格式校验
  • 提交到后端时,直接使用touristPlace.picture这个File对象即可

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 09:31:15