DEV Community

Cover image for Drag and Drop Image uploader using React-dropzone and Cloudinary
Johnpaul Eze
Johnpaul Eze

Posted on

Drag and Drop Image uploader using React-dropzone and Cloudinary

Media uploading has transitioned from conventional clicking and uploading to drag-and-drop functionality. Modern applications have adopted this new trend for a better user experience. In this tutorial, we will be implementing a drag-and-drop functionality in a react application.

To achieve that, we'll use the following technologies:

React-dropzone
react-dropzone is a set of React libraries that help developers to build complex drag-and-drop functionalities while keeping their components destructured. In other words, it is a React hook that makes it easy to construct drag-and-drop interfaces quickly rather than from scratch.

Cloudinary
cloudinary provides cloud-based image and video management services. It enables users to upload, store, manage, manipulate, and deliver photos and videos for websites and apps.

React
react is a free and open-source front-end JavaScript library for building user interfaces based on UI components. Facebook creates it.

What we will build
This series will focus on building a drag-and-drop zone for files and then uploading the dropped file(s) to a server. We'll use react-dropzone to implement the drag-and-drop functionalities, Afterwards, We’ll upload the files directly from the browser using Cloudinary Unsigned Upload.

Here's a demo of the end product in action:

Demo:
demo
Prerequisites

  • To follow this project, some experience with React.js and a cloudinary is required.
  • Node.js installed on the computer for local development.

Getting Started with React application
First, let’s run the following terminal command to create the react.js application in a folder called file_uploads:



$ npx create-react-app file_uploads


Enter fullscreen mode Exit fullscreen mode

Next, navigate into the application directory and install the dropzone npm package with the following commands:



$ cd file_uploads // to navigate into the project directory
$ npm install react-dropzone // to install the dropzone library


Enter fullscreen mode Exit fullscreen mode

Now, let’s start the application with the following command:



$ npm start


Enter fullscreen mode Exit fullscreen mode

React.js will start a live development server on http://localhost:3000.

Building the application
We want to create an area where, when we can click on it, the React-dropzone library will initiate a file selection dialog, allowing us to select and upload files.

The easiest way to get started with React Dropzone is to use the useDropzone hook. The useDropzone returns getRootProps, getInputProps, and isDragActive, which we can call to get the Drag and Drop API properties and pass those to our elements. The root element can be any element we want. For this example, we will use a <div>. The input element must be an <input>.

Next, let's create a component folder in the root directory of the project and create a Dropzone.js file with the following snippets:



//Dropzone.js
import React from 'react';
import { useDropzone } from 'react-dropzone';

function Dropzone() {
  const {
    getRootProps,
    getInputProps,
    isDragActive
  } = useDropzone({
    onDrop
  });
  return (
    ...
  );
}
export default Dropzone;


Enter fullscreen mode Exit fullscreen mode

Here, we imported useDropzone from 'react-dropzone' and destructured getRootProps, getInputProps and isDragActive from it.

Next, in the App.js, let's import and render the Dropzone.js component as shown below:



import React from 'react';
import Dropzone from './Dropzone';
function App() {
  return (
    <div>
      <Dropzone />
    </div>
  );
}

export default App;


Enter fullscreen mode Exit fullscreen mode

Next, in the return function of the Dropzone.js component, let’s return a div and input elements and pass getRootProps() and getInputProps() to them respectively. Also, we'll use the isDragActive to render the input label conditionally, like in the below:



//component/Dropzone.js
<div {...getRootProps()}>
  <input {...getInputProps()} />
 {isDragActive ? (
           <p className="dropzone">Drop your image files here</p>
          ) : (
           <p className="dropzone">
     Drag and drop some files here, or click to select files</p>
          )}  
</div>


Enter fullscreen mode Exit fullscreen mode

The getRootProps() — is a function that returns an object of the properties needed on the root element. It sets drag and drops API properties on the chosen root.

The properties and methods look like this:
Image description
These events allow the browser to monitor the users' drag and drop engagements.

The getInputProps() — is a function that returns an object of the properties needed on the input element.

Here are the properties and methods:
Image description
The isDragActive() — is a boolean, true if a file is dragged over the dropzone area and not included in acceptable file types but false if not.

Handling Drop Functionality
We can drag and drop files into our component, but we are not doing anything with these files yet.

The useDropzone hook takes an onDrop function as props to complete the drag and drop functionality and a config object as an optional parameter.

The onDrop property takes a callback function and calls it when the drop event occurs.

Now, let's create the onDrop function to preview the copy of the image being dragged and dropped into the dropzone and pass it to the useDropzone hook like in the below:



import React, { useState, useCallback, useEffect } from "react";
//other imports here

function Dropzone() {
  const [files, setFiles] = useState([]);

  const onDrop = useCallback((acceptedFiles) => {
    setFiles(
      acceptedFiles.map((file) =>
        Object.assign(file, {
          preview: URL.createObjectURL(file)
        })
      )
    );
  }, []);

  const { getRootProps, getInputProps, isDragActive } = useDropzone({
    onDrop,
    accept: "images/*"
  });

//return (); functiion here
}
export default Dropzone;


Enter fullscreen mode Exit fullscreen mode

In the snippets above, we:

  • Created files state constant with the useState hook to store the file object.
  • Wrapped the function with the useCallback hook to avoid triggering unnecessary re-renders.
  • Updated the files state by looping through the acceptedFiles parameter and calling Object.assign() and URL.createObjectURL() functions.
  • Passed the onDrop() function to the useDropzone hook and also gave the accept property and set it to a string ("images/*") to accept all image files.

Next, create a thumbs() function that will loop through the file's state constant and display a preview using the image tag. Update the Dropzone.js file with the following snippets:



//component/Dropzone.js
//imports here
function Dropzone() {
 //state constant here

//onDrop() function here

 //the Dropzone implementation here
  useEffect(() => {
    return () => files.forEach((file) => URL.revokeObjectURL(file.preview));
  }, [files]);

  const thumbs = files.map((file) => (
    <div key={file.name}>
      <div>
        <img
          src={file.preview}
          onLoad={() => {
            URL.revokeObjectURL(file.preview);
          }}
          alt=""
        />
      </div>
    </div>
  ));
  return (
    <div className="App">
      <div>
        <div {...getRootProps()}>
          //input and p tags here
        </div>
      </div>

      <aside>{thumbs}</aside>
    </div>
  );
}
export default Dropzone;


Enter fullscreen mode Exit fullscreen mode

Here, we created the thumbs() function, rendered it in the return() function, and used the useEffect hook to prevent memory leaks and avoid unnecessarily storing the preview.

Now when we drop a file (or files), the file will be appended to the state and displayed in a preview.

Upload to cloudinary with unsigned upload
To upload the file to Cloudinary, log in or create a free account here. From the Dashboard, click on the Settings icon and navigate to uploads.

CloudImage
Next, scroll down to upload presets, add an unsigned preset, choose a folder to upload the files, and select a name for the preset.

CloudImage2
Learn more about Cloudinary unsigned uploads.

Next, let's create a handleUpload() to upload the file to Cloudinary and render a button that will trigger the handleUpload() in the return(). Update the Dropzone.js file with the following snippets:



//component/Dropzone.js
//imports here
function Dropzone() {
  const [files, setFiles] = useState([]);

// onDrop() function here

  // useDropzone hook here

 // thumbs() function here

 //useEffect hook here

  const handleUpload = () => {
    const url = "https://api.cloudinary.com/v1_1/johnpaul/image/upload";
    const formData = new FormData();
    let file = files[0];
    formData.append("file", file);
    formData.append("upload_preset", "dryqolej");
    fetch(url, {
      method: "POST",
      body: formData
    })
      .then((response) => {
        return response.json();
      })
      .then((data) => {
        console.log(data);
      });
  };

  return (
    <div className="App">
      <div>
        <div {...getRootProps()}>
    // input and p tags here
        </div>
      </div>
      {files.length > 0 && (
        <button className="button" onClick={handleUpload}>
          Upload
        </button>
      )}
      <aside>{thumbs}</aside>
    </div>
  );
}
export default Dropzone;


Enter fullscreen mode Exit fullscreen mode

In the snippets above, we created the handleUpload() function and conditionally rendered the Upload button if there is a file in the files state. Then passed the handleUpload() to the onClick event of the button.

Now, when we drag and drop a file in the drop area, we'll see a file preview. If we click the Upload button and go over to our console or our media library, we will see the image object Uploaded to Cloudinary.

The final result will look like the GIF shown below.

demo3

Conclusion

In this tutorial, we explored react-dropzone and how it can be integrated into a React application to offer advanced drag and drop functionalities to media uploads. Implementing such a fantastic user experience feature in our React application should now be a thing of the past. I hope this tutorial is helpful. The complete source code for this tutorial is available on Github
.

Resources
These resources might be useful

Top comments (0)