How to remove file from react-dropzone?
Asked Answered
B

5

17

Hope you help me with this, I'm using the useDropzone hook from react-dropzone and I don't know how to make a remove file button for each file.

How can I remove a single file?

This is my code:

function DragFile(props) {
  const { acceptedFiles, rejectedFiles, getRootProps, getInputProps } = useDropzone({
    accept: 'image/jpeg, image/png, .pdf',
    maxSize: 3000000,
    multiple: true
  });

  const acceptedFilesItems = acceptedFiles.map(file => (
    <Col xs={12} md={4} key={file.path} className="card-file">
      <div className="file-extension">{file.path.substring(file.path.indexOf('.') + 1)}</div>
      <span>{file.path.substring(0, file.path.indexOf('.'))} <small>{(file.size / 1000).toFixed(2)} Kb</small></span>
      <button className="delete">DeleteButton</button>
    </Col>
  ));

  const rejectedFilesItems = rejectedFiles.map(file => (
    <li key={file.path}>
      {file.path.substring(0, file.path.indexOf('.'))} - {file.size / 1000} Kb
    </li>
  ));

  return (
    <div>
      <div {...getRootProps({ className: 'dropzone drag-n-drop' })}>
        <input id="file-claim" {...getInputProps()} />
        <img src={uploadSrc} alt="Subir archivo" />
        <p>Drag files here (PDF, JPG, PNG).</p>
      </div>
      <Row className="accepted-files">
        {acceptedFilesItems}
      </Row>
    </div>
  );
}

export default DragFile;
Barbel answered 7/5, 2019 at 15:14 Comment(0)
N
18

Let me just add this code, because the other answers here were unclear to me:

You need to make your own myFiles state and update that with the onDrop function, then use your remove function to remove that file from your local state.

import React, { useState, useCallback } from "react"
import { useDropzone } from "react-dropzone"

function Basic(props) {
  const [myFiles, setMyFiles] = useState([])

  const onDrop = useCallback(acceptedFiles => {
    setMyFiles([...myFiles, ...acceptedFiles])
  }, [myFiles])

  const { getRootProps, getInputProps } = useDropzone({
    onDrop,
  })

  const removeFile = file => () => {
    const newFiles = [...myFiles]
    newFiles.splice(newFiles.indexOf(file), 1)
    setMyFiles(newFiles)
  }

  const removeAll = () => {
    setMyFiles([])
  }

  const files = myFiles.map(file => (
    <li key={file.path}>
      {file.path} - {file.size} bytes{" "}
      <button onClick={removeFile(file)}>Remove File</button>
    </li>
  ))

  return (
    <section className="container">
      <div {...getRootProps({ className: "dropzone" })}>
        <input {...getInputProps()} />
        <p>Drag 'n' drop some files here, or click to select files</p>
      </div>
      <aside>
        <h4>Files</h4>
        <ul>{files}</ul>
      </aside>
      {files.length > 0 && <button onClick={removeAll}>Remove All</button>}
    </section>
  )
}

export default Basic
Nikolaos answered 2/3, 2022 at 5:36 Comment(2)
I think this answer is the best. No issues and clear.Jacey
For some reason when I use your code the setMyFiles does not work. Any ideas?Turcotte
D
6

You've probably already got this working but you just need to attach this to the click handler:

const remove = file => {
  const newFiles = [...files];     // make a var for the new array
  newFiles.splice(file, 1);        // remove the file from the array
  setFiles(newFiles);              // update the state
};

And pass the number in your map: acceptedFiles.map(file... should be acceptedFiles.map((file, i)....

Then have <button type="button" onClick={() => remove(i)> DeleteButton</button> where i is the number of the file in the array.

Dashboard answered 21/10, 2019 at 14:7 Comment(4)
Where is the spread operator on the newFiles variable coming from? I tried using acceptedFiles but couldn't get it working. Any suggestions?Evincive
Where and what is the definition of setFiles? Is it part of the useDropZone hook?Johannisberger
your code should be corrected like this <button type="button" onClick={() => remove(i) }>Proposition
in your code [...files] coming from the state value you set from the onDrop function.Proposition
S
3

I hope this will help you :

import React, { useState, useEffect, useCallback } from 'react'
import { useDropzone } from 'react-dropzone'

const CreateFileUpload = () => {
  const onDrop = useCallback(acceptedFiles => {
    // Do something with the files
  }, [])
  const { getRootProps, getInputProps, isDragActive, acceptedFiles } = useDropzone({ onDrop, accept: '.png, .jpeg' })
  const files = acceptedFiles.map((file, i) => (
    <li key={file.path} className="selected-file-item">
      {file.path}  <i className="fa fa-trash text-red" onClick={() => remove(i)}></i>
    </li>
  ));
  const remove = file => {
    const newFiles = [...files];     // make a var for the new array
    acceptedFiles.splice(file, 1);        // remove the file from the array
  };
  return (
    <div>
      <div {...getRootProps()} className="dropzone-main">
        <div
          className="ntc-start-files-dropzone"
          aria-disabled="false"
        >
        </div>
        <button className="add-button" type="button">
          <i className="fa fa-plus"></i>
        </button>
        <h3 className="upload-title">
          <span></span>
        </h3>
        <input
          type="file"
          multiple=""
          autocomplete="off"
          className="inp-file"
          // onChange={uploadFile}
          multiple
          {...getInputProps()}
        />
        {isDragActive ?
          <div></div>
          :
          <div>
            <p>  Upload files  </p>
          </div>
        }
      </div>
      <aside>
        {files.length > 0 ? <h5>Selected Files</h5> : <h5></h5>}
        <ul>{files}</ul>
      </aside>
    </div>
  )
}
export default CreateFileUpload
Sphery answered 16/10, 2020 at 11:3 Comment(1)
In the example you do not use newFilesJohannisberger
T
1

All the answers here have a flaw -- if you add a file, remove it, and then add the same file again it won't work because there's no change event triggered on the file input (because you didn't clear it out)

need to grab inputRef from the hook and clear it in the remove button

function DragFile(props) {
  const [myFile, setMyFile] = useState();
  const { getRootProps, getInputProps, inputRef } = useDropzone({
    onDrop: () => { /* setMyFile */ }
    ...
  });

  return (
    <div>
      {!myFile ? (
        <div {...getRootProps()}>
          <input id="file-claim" {...getInputProps()} />
          drop files here
        </div>
      ) : (
        {myFile.filename}
        <button onClick={() => {
          setMyFile(undefined);
          inputRef.current.value = "";
        }}>remove</button>
      )}
    </div>
  );
}

export default DragFile;
Toga answered 2/5 at 14:43 Comment(0)
E
0

When you drop your files, add that data to your state and it should give you access to the data so that you can delete.

Roughly:

onDrop = (files) => {
  // use a foreach loop get the file name using Object.keys
  // setState with the file names
  // whatever else you need to do to process the file
}

handleDelete = () => {
  // use the file names from your state to delete the files
}

somewhere in there you'll have to combine it all with jsx. you'll also need to keep it sync'd with whatever you're sending to the server. that should all be done with your component state.

Effendi answered 18/7, 2019 at 19:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.