reactjs - Reset File Input Refs Across Components to Allow Re-uploading - Stack Overflow

admin2025-05-01  2

I only came across very hacky solutions, so maybe someone has a better idea how to solve it.

Here's what I'm trying to do:

  • The UploadComponent lets the user select files using refs.
  • Once a file is selected, it’s passed to the parent component (App), which keeps track of the uploaded files.
  • The FilePreviewComponent displays the uploaded files and allows the user to delete a file. When a file is deleted, I want to reset the file input refs in the UploadComponent so that the same file can be uploaded again.

For now I couldn't find any solution to reset refs cross-component. Here is code example:

 const App = () => {
  const { control, handleSubmit, setValue, getValues } = useForm();
  const [selectedFiles, setSelectedFiles] = useState([]);

  const onSubmit = (data) => {
    console.log(data);
  };

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      {/* Upload Component */}
      <Controller
        name="files"
        control={control}
        render={({ field: { value, onChange } }) => (
          <UploadComponent
            onFileSelected={(files) => {
              const updatedFiles = [...value, ...files];
              onChange(updatedFiles);
              setSelectedFiles(updatedFiles);
            }}
          />
        )}
      />

      {/* File Preview Component */}
      <Controller
        name="files"
        control={control}
        render={({ field: { value } }) => (
          <FilePreviewComponent
            files={value}
            onDelete={(fileToDelete) => {
              const updatedFiles = value.filter((file) => file.uri !== fileToDelete.uri);
              setSelectedFiles(updatedFiles);
              setValue("files", updatedFiles);
            }}
          />
        )}
      />

      <button type="submit">Submit</button>
    </form>
  );
};

export default App;

And here is the upload component.

const UploadComponent = ({ onFileSelected }) => {
 
  const fileInputRef = useRef(null);


  const handleFileUpload = (e) => {
    const files = Array.from(e.target.files).map((file) => ({
      uri: URL.createObjectURL(file), // Create a temporary URL for preview
      name: file.name,
      type: file.type,
      blob: file, 
    }));
    onFileSelected(files); 
  };

  return (
    <div>
      {/* Button to trigger file input */}
      <button onClick={() => fileInputRef.current.click()}>Upload File</button>

      {/* Hidden file input triggered by button */}
      <input
        ref={fileInputRef}
        type="file"
        accept="image/*,application/pdf" 
        style={{ display: "none" }} 
        onChange={handleFileUpload} 
      />
    </div>
  );
};

export default UploadComponent;

I only came across very hacky solutions, so maybe someone has a better idea how to solve it.

Here's what I'm trying to do:

  • The UploadComponent lets the user select files using refs.
  • Once a file is selected, it’s passed to the parent component (App), which keeps track of the uploaded files.
  • The FilePreviewComponent displays the uploaded files and allows the user to delete a file. When a file is deleted, I want to reset the file input refs in the UploadComponent so that the same file can be uploaded again.

For now I couldn't find any solution to reset refs cross-component. Here is code example:

 const App = () => {
  const { control, handleSubmit, setValue, getValues } = useForm();
  const [selectedFiles, setSelectedFiles] = useState([]);

  const onSubmit = (data) => {
    console.log(data);
  };

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      {/* Upload Component */}
      <Controller
        name="files"
        control={control}
        render={({ field: { value, onChange } }) => (
          <UploadComponent
            onFileSelected={(files) => {
              const updatedFiles = [...value, ...files];
              onChange(updatedFiles);
              setSelectedFiles(updatedFiles);
            }}
          />
        )}
      />

      {/* File Preview Component */}
      <Controller
        name="files"
        control={control}
        render={({ field: { value } }) => (
          <FilePreviewComponent
            files={value}
            onDelete={(fileToDelete) => {
              const updatedFiles = value.filter((file) => file.uri !== fileToDelete.uri);
              setSelectedFiles(updatedFiles);
              setValue("files", updatedFiles);
            }}
          />
        )}
      />

      <button type="submit">Submit</button>
    </form>
  );
};

export default App;

And here is the upload component.

const UploadComponent = ({ onFileSelected }) => {
 
  const fileInputRef = useRef(null);


  const handleFileUpload = (e) => {
    const files = Array.from(e.target.files).map((file) => ({
      uri: URL.createObjectURL(file), // Create a temporary URL for preview
      name: file.name,
      type: file.type,
      blob: file, 
    }));
    onFileSelected(files); 
  };

  return (
    <div>
      {/* Button to trigger file input */}
      <button onClick={() => fileInputRef.current.click()}>Upload File</button>

      {/* Hidden file input triggered by button */}
      <input
        ref={fileInputRef}
        type="file"
        accept="image/*,application/pdf" 
        style={{ display: "none" }} 
        onChange={handleFileUpload} 
      />
    </div>
  );
};

export default UploadComponent;
Share Improve this question asked Jan 2 at 22:18 Katharina SchreiberKatharina Schreiber 1,3713 gold badges19 silver badges44 bronze badges 1
  • You can change the key on the UploadComponent after removing a file and that will trigger a re-mount so a new state for that component. Alternatively, but similarly, you can update the key on the input so that will be re-mounted. – Gabriele Petrioli Commented Jan 2 at 22:40
Add a comment  | 

1 Answer 1

Reset to default 1

The issue reported here may not be related with ref. It may be an issue related with input element itself.

What is meant here is, a retry of a file upload also suffers from the same issue as it is not allowed. Furthermore, when a file has been uploaded, but before confirming the form, the same file needs to be uploaded again - due to some reason. The below html copied from the post may not support this use case.

<input
 ref={fileInputRef}
 type="file"
 accept="image/*,application/pdf" 
 style={{ display: "none" }} 
 onChange={handleFileUpload} 
/>

However the same use case may be possible when the value property is also used. It can also be done by manipulating the event object as well.

Please see below a sample code below, showing the same.

App.js

export default function App() {
  return (
    <>
      <label>Retry a same file upload : Disallowed</label>
      <input type="file" onChange={(e) => console.log(e.target.value)}></input>
      <br></br>
      <label>Retry a same file upload : allowed method 1</label>
      <input
        type="file"
        value=""
        onChange={(e) => console.log(e.target.value)}
      ></input>
      <br></br>
      <label>Retry a same file upload : allowed method 2</label>
      <input
        type="file"
        onChange={(e) => {
          console.log(e.target.value);
          e.target.value = '';
        }}
      ></input>
      <br></br>
    </>
  );
}

Test plan

After the app has been loaded, each of three upload buttons will be clicked twice to upload a same file.

Test results

The console logs generated

// C:\somefile.txt - logged only once
// C:\somefile.txt - logged twice 
// C:\somefile.txt - logged twice

Observation

The logs show that, the first input declaration does not allow retry. However, the next two input declarations do support that. Of which, the first one is implemented by value property, and the second one is by manipulating value property through scripting.

Solution proposal

Perhaps after applying one of the options discussed above, the reported issue may be resolved. The reason for this proposal is, as we know, ref is just an access to a DOM element, it does not have anything of its own. Therefore if the DOM element is capable of doing something, then the ref to it will also be reflecting the same.

Citation:

Can't upload same file twice

转载请注明原文地址:http://anycun.com/QandA/1746094398a91585.html