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

ReactJS文件上传需两次选择才生效问题求助

问题描述

首次点击按钮选择文件并上传成功后,再次选择文件时需点击choose a file两次才能生效,否则会显示No file selected.。

相关代码

const FactoryContactUpload = () => {
  const [selectedFile, setSelectedFile] = useState(null);
  const handleFileChange = (event) => {
    // Handle the file change event
    const file = event.target.files[0];
    setSelectedFile(file);
  };
  const handleFileClick = (event) => {
    setShowAlert(false);
  };

  const handleUpload = async () => {
    // Handle the upload event
    if (selectedFile) {
      const formData = new FormData();
      formData.append("file", selectedFile);
      const token = await acquireTokenSilent(instance);
      apiClient
        .post("/factorycontact/upload", formData, {
          headers: {
            "Content-Type": "multipart/form-data",
            Authorization: `Bearer ${token}`,
          },
        })
        .then((response) => {
          // Handle the API response
          setShowAlert(true);
          setAlertType("success");
          setAlertMessage(response.data.message || "");
        })
        .catch((error) => {
          // Handle errors
          setShowAlert(true);
          setAlertType("error");
          setAlertMessage(error.response?.data?.message || "An error occurred");
        });
    } else {
      setShowAlert(true);
      setAlertType("info");
      setAlertMessage("No file selected.");
    }
  };

  return (
    <div>
      <>
        <input
          type="file"
          onChange={handleFileChange}
          onClick={handleFileClick}
        />
        <button onClick={handleUpload}>Upload</button>
        <br />
        <br />
      </>
      {showAlert && <Alert type={alertType} message={alertMessage} />}
    </div>
  );
};

问题原因

核心问题是上传完成后未重置文件输入框的状态:

  • 上传成功后,selectedFile状态仍保留着旧文件的引用,同时浏览器文件输入框的内部值也未清空;
  • 当用户再次选择同一文件时,浏览器会判定输入框值未发生变化,不会触发onChange事件;即使选择不同文件,也会因为组件状态与DOM状态不一致,导致文件选择逻辑异常。

解决方案

需要在上传成功后同步清空文件状态并重置输入框DOM,确保下次选择文件时onChange事件能正常触发。修改后的代码如下:

import { useState, useRef } from 'react';

const FactoryContactUpload = () => {
  const [selectedFile, setSelectedFile] = useState(null);
  // 添加ref用于获取文件输入框DOM
  const fileInputRef = useRef(null);
  // 补充原代码缺失的状态定义
  const [showAlert, setShowAlert] = useState(false);
  const [alertType, setAlertType] = useState('');
  const [alertMessage, setAlertMessage] = useState('');

  const handleFileChange = (event) => {
    const file = event.target.files[0];
    setSelectedFile(file);
  };

  const handleFileClick = (event) => {
    setShowAlert(false);
  };

  const handleUpload = async () => {
    if (selectedFile) {
      const formData = new FormData();
      formData.append("file", selectedFile);
      const token = await acquireTokenSilent(instance);
      apiClient
        .post("/factorycontact/upload", formData, {
          headers: {
            "Content-Type": "multipart/form-data",
            Authorization: `Bearer ${token}`,
          },
        })
        .then((response) => {
          // 上传成功后清空文件状态并重置输入框
          setSelectedFile(null);
          if (fileInputRef.current) {
            fileInputRef.current.value = '';
          }
          // 提示信息更新
          setShowAlert(true);
          setAlertType("success");
          setAlertMessage(response.data.message || "");
        })
        .catch((error) => {
          setShowAlert(true);
          setAlertType("error");
          setAlertMessage(error.response?.data?.message || "An error occurred");
        });
    } else {
      setShowAlert(true);
      setAlertType("info");
      setAlertMessage("No file selected.");
    }
  };

  return (
    <div>
      <>
        <input
          type="file"
          onChange={handleFileChange}
          onClick={handleFileClick}
          ref={fileInputRef} // 绑定ref到输入框
        />
        <button onClick={handleUpload}>Upload</button>
        <br />
        <br />
      </>
      {showAlert && <Alert type={alertType} message={alertMessage} />}
    </div>
  );
};

修改说明

  1. 添加fileInputRef:通过React ref直接操作文件输入框DOM,上传成功后将其value设为空字符串,强制浏览器重置输入框状态;
  2. 清空文件状态:上传成功后调用setSelectedFile(null),确保组件状态与输入框DOM状态同步;
  3. 补充缺失状态:原代码中未显示showAlert等状态定义,需确保组件中已存在这些状态以保证逻辑正常运行。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 01:50:22