React Dropzone: A Thorough Introduction

Fatemeh Paghar - May 14 '23 - - Dev Community

The uploading of files is a common feature found in most web applications, and drag and drop functionality has become a convenient way to achieve this. To implement this feature in a React application, the react-dropzone module is a popular choice due to its rich set of features and customization options that can be tailored to suit individual needs.

This article aims to provide an in-depth understanding of the react-dropzone module, explore various methods of utilizing its functionality to implement drag and drop, and provide examples of customizing its behavior.

React Dropzone Module: An Introduction

React Dropzone, also known as react-dropzone, is a React module that allows for easy creation of drag-and-drop functionality within a React application. This module simplifies the user's file uploading experience, enabling them to drag files from their file explorer and drop them into the application for immediate upload. With a plethora of customization options, React Dropzone is a feature-rich module. Users can restrict the types of files that can be uploaded, as well as upload multiple files simultaneously, among other capabilities.

How to Install, and Modeling a Basic React Dropzone File Picker

To add the react-dropzone module to an application, we can utilize the following command.

npm install react-dropzone

This module is ideal for any application that involves file uploading, such as a university entrance application website, a job application site, or a post uploading platform. Our initial step is to construct a basic file picker with React Dropzone.

Initially, we should import the React Dropzone library below all other imports in the file. Following this, we can include the React Dropzone component in the render method's return statement, as well as an onDrop method above it. The resulting code should resemble the following:

import React, { Component } from 'react';
import Dropzone from 'react-dropzone'

class App extends Component {

  onDrop = (acceptedFiles) => {
    console.log(acceptedFiles);
  }

  render() {
    return (
      <div className="text-center mt-5">
        <Dropzone onDrop={this.onDrop}>
          {({getRootProps, getInputProps}) => (
            <div {...getRootProps()}>
              <input {...getInputProps()} />
              Click me to upload a file!
            </div>
          )}
        </Dropzone>
      </div>
    );
  }
}

export default App;
Enter fullscreen mode Exit fullscreen mode

React Dropzone requires only one method to be passed into the onDrop prop to handle file selection. To maintain simplicity, we will name the method onDrop to match the prop name.

The onDrop method has a single parameter, acceptedFiles, which we will currently log to the console for testing purposes. After saving the component, we can open our browser and navigate to our running React app.

Clicking the text label will open a file picker window, which is a great start! However, selecting a file to upload will not have any effect at this time. To make file uploads functional, we need to send the file to a server, which will be covered in a future tutorial.

Render Props

React Dropzone's appearance may appear distinct from other React components you've encountered because it employs the Render Props technique.

The Render Prop Function modifies the HTML within the Dropzone component based on its current state.

To demonstrate this concept, we'll add a variable to the Render Prop function named isDragActive. This variable grants us access to the Dropzone component's current drag state.

With the isDragActive state available, we can alter the text value of the label to display something distinct when a file is dragged over the component.

<Dropzone onDrop={this.onDrop}>
  {({getRootProps, getInputProps, isDragActive}) => (
    <div {...getRootProps()}>
      <input {...getInputProps()} />
      {isDragActive ? "Drop it like it's hot!" : 'Click me or drag a file to upload!'}
    </div>
  )}
</Dropzone>
Enter fullscreen mode Exit fullscreen mode

The code snippet mentioned above demonstrates an inline conditional that examines whether isDragActive is true or not. If it is true, the text "Drop it like it's hot" is displayed, and if it is false, the text "Click me or drag a file to upload!" is shown.

To Allow Specific Types of Files

At present, our file selector permits us to choose any file type to upload.

However, depending on the purpose of the file picker, we may want to restrict the selection to specific file types, such as only .JPG files, or only .XLS and .DOCX files.

To achieve this, we can use the accept prop and add it after onDrop within the Dropzone component declaration.

<Dropzone
  onDrop={this.onDrop}
  accept="image/png, image/gif"
>
...
</Dropzone>
Enter fullscreen mode Exit fullscreen mode

File types are represented as MIME types, and Mozilla provides a comprehensive list of MIME types.

To enhance the user experience of our file picker, we can display a message when the user attempts to upload a file type that is not accepted.

We can accomplish this by adding another render prop called isDragRejected and modifying the inline conditional logic accordingly.

<Dropzone
  onDrop={this.onDrop}
  accept="image/png"
>
  {({getRootProps, getInputProps, isDragActive, isDragReject}) => (
    <div {...getRootProps()}>
      <input {...getInputProps()} />
      {!isDragActive && 'Click here or drop a file to upload!'}
      {isDragActive && !isDragReject && "Drop it like it's hot!"}
      {isDragReject && "File type not accepted, sorry!"}
    </div>
  )}
</Dropzone>
Enter fullscreen mode Exit fullscreen mode

Finally, we can save the file and test it by attempting to drag a .JPG file onto the file picker in the browser. When we do so, a message is displayed indicating that our file picker does not accept that type of file.

The Highest and Lowest File Size

Setting a limit on the file size is crucial to prevent users from uploading excessively large files and overloading your server.

React Dropzone offers two props, minSize and maxSize, which allow you to set the minimum and maximum file size in bytes.

To specify a maximum file size of 5MB or less, add the minSize and maxSize props to the Dropzone component below the accept prop.

App.js
<Dropzone
  onDrop={this.onDrop}
  accept="image/png"
  minSize={0}
  maxSize={5242880}
>
  ...
</Dropzone>
Enter fullscreen mode Exit fullscreen mode

To enhance the user experience, let's add some code to our file input component that verifies the maximum file size and displays an error message if the uploaded file exceeds the limit.

render() {
  const maxSize = 1048576;
  return (
    <div className="text-center mt-5">
      <Dropzone
        onDrop={this.onDrop}
        accept="image/png"
        minSize={0}
        maxSize={maxSize}
      >
        {({getRootProps, getInputProps, isDragActive, isDragReject, rejectedFiles}) => {
          const isFileTooLarge = rejectedFiles.length > 0 && rejectedFiles[0].size > maxSize;
          return (
            <div {...getRootProps()}>
              <input {...getInputProps()} />
              {!isDragActive && 'Click here or drop a file to upload!'}
              {isDragActive && !isDragReject && "Drop it like it's hot!"}
              {isDragReject && "File type not accepted, sorry!"}
              {isFileTooLarge && (
                <div className="text-danger mt-2">
                  File is too large.
                </div>
              )}
            </div>
          )}
        }
      </Dropzone>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Despite the appearance of a significant amount of code, it is only a few lines (usually less than 10).

Here are the instructions:

  • We create a constant named "maxSize" and set its value to 1MB at the beginning of the render method.
  • We use the "maxSize" constant in the "maxSize" prop of the Dropzone component.
  • We add a new render prop called "rejectedFiles" to the Dropzone component.
  • After the render prop function in the Dropzone component, we define another constant called "isFileTooLarge". It retrieves the first file from the "rejectedFiles" array and checks if its size is greater than the "maxSize" constant we defined earlier.
  • We then use a conditional statement to check if "isFileTooLarge" is true and display the message "File is too large." in red.

Let's test the functionality in the browser!

More than One File in Action!

The final feature we will discuss about React Dropzone is the capability to upload multiple files. It is a straightforward process and does not involve any changes to the render prop function. To enable this feature, we just need to add the "multiple" prop to the React Dropzone component declaration.

<Dropzone
  onDrop={this.onDrop}
  accept="image/png"
  minSize={0}
  maxSize={maxSize}
  multiple
>
  ...
</Dropzone>
Enter fullscreen mode Exit fullscreen mode

How to Use Hooks in React Dropzone

The release of React Hooks and the updated version of react-dropzone library with the custom useDropzone Hook has prompted a rewrite of the entire component as a functional one.
This involves using the useDropzone custom hook provided by react dropzone.

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

const App = () => {
  const maxSize = 1048576;

  const onDrop = useCallback(acceptedFiles => {
    console.log(acceptedFiles);
  }, []);

  const { isDragActive, getRootProps, getInputProps, isDragReject, acceptedFiles, rejectedFiles } = useDropzone({
    onDrop,
    accept: 'image/png',
    minSize: 0,
    maxSize,
  });

  const isFileTooLarge = rejectedFiles.length > 0 && rejectedFiles[0].size > maxSize;

  return (
    <div className="container text-center mt-5">
      <div {...getRootProps()}>
        <input {...getInputProps()} />
        {!isDragActive && 'Click here or drop a file to upload!'}
        {isDragActive && !isDragReject && "Drop it like it's hot!"}
        {isDragReject && "File type not accepted, sorry!"}
        {isFileTooLarge && (
          <div className="text-danger mt-2">
            File is too large.
          </div>
        )}
      </div>
    </div>
  );
};

export default App;
Enter fullscreen mode Exit fullscreen mode

How to Show a List of Accepted Files

The availability of React Hooks and the updated version of react-dropzone library, which includes a custom useDropzone Hook, has resulted in a complete rewrite of the component as a functional one.
This rewrite entails utilizing the useDropzone custom hook provided by react-dropzone.

...
<ul className="list-group mt-2">
  {acceptedFiles.length > 0 && acceptedFiles.map(acceptedFile => (
    <li className="list-group-item list-group-item-success">
      {acceptedFile.name}
    </li>
  ))}
</ul>
...
Enter fullscreen mode Exit fullscreen mode

Conclusion

To sum up, react-dropzone is a widely used React module that enables drag and drop functionality in web applications. This package provides many customization options, including the ability to limit the size of uploaded files and allowing specific file types to upload. Additionally, the package offers the ability to upload multiple files and display a list of uploaded files easily. With react-dropzone, we don't have to rely on the HTML drag and drop API, which was previously the most common way to upload files using drag and drop.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .