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

React图片上传组件二次上传异常:重复选中首次文件问题排查

问题分析与解决方案

问题根源

你遇到的第二次上传复用首次文件的问题,核心原因是:

  • React的合成事件e会被异步回收,在toast.promise的success回调中操作e.target.files = null完全无效,无法正确重置文件输入框的状态。
  • 虽用ref重置value = "",但操作时机和方式不够严谨,导致快速连续上传时,输入框内部状态未及时同步。

修复步骤

  1. 统一通过ref操作真实DOM重置输入框
    移除success回调中无效的e.target.files = null,直接通过ref清空输入框value,确保无论成功失败都执行重置。
  2. 释放ObjectURL避免内存泄漏(可选但推荐)
    每次设置新预览图时,释放旧的ObjectURL,减少内存占用。
  3. 全分支覆盖重置逻辑
    文件校验失败、上传成功/失败的所有场景,都添加输入框重置操作,保证每次操作后输入框状态干净。

修改后的代码

function handleUpload(e: React.ChangeEvent<HTMLInputElement>) {
  const loaderToast = toast.loading("Uploader...");
  const fileInput = e.target;
  const file = fileInput.files?.[0];
  if (!file) {
    toast.dismiss(loaderToast);
    return;
  }

  const fileExt = file.name.split(".").pop()?.toLowerCase();
  const fileSize = file.size;

  // 文件大小校验
  if (fileSize > 15000000) {
    toast.error("Billedet må ikke være større end 15MB!");
    toast.dismiss(loaderToast);
    fileInput.value = "";
    return;
  }

  // 文件格式校验
  if (!["jpg", "png", "jpeg"].includes(fileExt || "")) {
    toast.error(`Billedet skal være i jpg, png eller jpeg format! (当前格式: ${fileExt})`, { duration: 5000 });
    toast.dismiss(loaderToast);
    fileInput.value = "";
    return;
  }

  // 释放旧预览URL
  const oldPreview = props.profilePicturePreview;
  if (oldPreview) {
    URL.revokeObjectURL(oldPreview);
  }

  // 设置预览图和临时文件
  props.setprofilePicturePreview(URL.createObjectURL(file));
  props.setprofilePicture(file);
  toast.dismiss(loaderToast);

  toast.promise(
    CLIENT_API.put(
      "merchant/profile_picture/",
      { image: file },
      { headers: { "Content-Type": "multipart/form-data" } }
    ).then((res) => {
      const updatedUser = { ...user, profile_picture: res.data.new };
      sessionStorage.setItem("user", JSON.stringify(updatedUser));
      setUser(updatedUser);
    }),
    {
      loading: "Opdatere din profil...",
      success: () => {
        fileInput.value = "";
        return `Dit profilbillede er opdateret`;
      },
      error: (error) => {
        fileInput.value = "";
        return error?.response?.data?.detail || error?.response?.data?.message || "上传失败";
      },
    },
    { error: { duration: 5000 } }
  );
}

// 输入框部分保持不变
<input
  type="file"
  ref={props.fileUpload}
  accept="image/png, image/jpeg, image/jpg"
  onChange={handleUpload}
  hidden
/>

关键修改点说明

  • 用fileInput本地引用操作真实DOM,避开React合成事件异步回收的问题。
  • 格式校验时统一转小写,避免大小写判断失误(比如用户上传.JPG格式)。
  • 全分支覆盖输入框重置,确保每次操作后输入框状态归零,不会残留旧文件信息。

内容的提问来源于stack exchange,提问作者Charlie Østergaard

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 01:25:19