0

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;
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. Commented Jan 2 at 22:40

1 Answer 1

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

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you for your confirmation and vote.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.