React图片上传组件二次上传异常:重复选中首次文件问题排查
问题分析与解决方案
问题根源
你遇到的第二次上传复用首次文件的问题,核心原因是:
- React的合成事件
e会被异步回收,在toast.promise的success回调中操作e.target.files = null完全无效,无法正确重置文件输入框的状态。 - 虽用ref重置
value = "",但操作时机和方式不够严谨,导致快速连续上传时,输入框内部状态未及时同步。
修复步骤
- 统一通过ref操作真实DOM重置输入框
移除success回调中无效的e.target.files = null,直接通过ref清空输入框value,确保无论成功失败都执行重置。 - 释放ObjectURL避免内存泄漏(可选但推荐)
每次设置新预览图时,释放旧的ObjectURL,减少内存占用。 - 全分支覆盖重置逻辑
文件校验失败、上传成功/失败的所有场景,都添加输入框重置操作,保证每次操作后输入框状态干净。
修改后的代码
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
相关产品推荐
相关产品推荐

