Search code examples
javascriptreactjsfile-uploadreact-dropzone

react-dropzone - accessing files added by click not drop


I am using the react-dropzone basic example (react-dropzone basic)

import React from 'react';
import {useDropzone} from 'react-dropzone';

function Basic(props) {
  const {acceptedFiles, getRootProps, getInputProps} = useDropzone();

  const files = acceptedFiles.map(file => (
    <li key={file.path}>
      {file.path} - {file.size} bytes
    </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>
    </section>
  );
}

<Basic />

This is working as expected, until I use the click method to add a file. When adding a file using click the acceptedFiles do not register the file (I have added an onChange handler and event.target.files shows the file so it is defintely being added to the overall FileList).

Due to this I cannot display the file added by click details in the Files <ul> as I would with a dragged file. I assume the same would be true for fileRejections but I have not implemented it yet.

I hope I'm missing something obvious as I would assume that dropzone handles both drag and click behaviour?

Appreciate someone pointing me in the right direction if possible.


Solution

  • The above code handles both drag and drop, however it only gives you the latest added files and not the entire list of uploaded file.

    To implement it correctly you can maintain a state and add an onDrop function to useDropzone in which you will append the files and update state

    function Basic(props) {
      const [files, setFiles] = React.useState([]);
      const onDrop = React.useCallback(acceptedFiles => {
        setFiles(prev => [...prev, ...acceptedFiles]);
      }, []);
      const { getRootProps, getInputProps } = useDropzone({ onDrop });
    
      const fileList = files.map(file => (
        <li key={file.path}>
          {file.path} - {file.size} bytes
        </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>{fileList}</ul>
          </aside>
        </section>
      );
    }
    

    Working demo