Drag-and-drop uploads in React (video tutorial)
Last updated: Nov-13-2024
On this page:
- Overview
- Video tutorial
- Tutorial contents
- Introduction to file upload in React
- Setting up drag-and-drop with react-dropzone
- Spreading react-dropzone props in a <div>
- Accessing selected files
- Setting state for data URL
- Implementing visual feedback for drag-and-drop
- Setting Up Cloudinary for file uploads
- Creating the uploadImage function
- Displaying the uploaded file
- Testing drag-and-drop functionality
- Keep learning
Overview
Learn how to implement drag-and-drop uploads to Cloudinary in your React app using the react-dropzone
library.
Video tutorial
View the code
You can find the code from this tutorial in GitHub.Tutorial contents
This tutorial presents the following topics. Click a timestamp to jump to that part of the video.
Introduction to file upload in React
The traditional way to select files on websites is using a file picker input element. However, to achieve drag-and-drop functionality, you can use the browser's drag-and-drop API or a library like react-dropzone , which simplifies this process. This tutorial demonstrates how to set up react-dropzone , import its component, and use the useDropzone hook with an onDrop callback function to handle selected files and preview the selected image. |
|
Setting up drag-and-drop with react-dropzone
Ensure your React application is set up, then install react-dropzone with npm install react-dropzone . Import the useDropzone hook by adding import { useDropzone } from "react-dropzone" . Set up the onDrop callback to log selected files, and destructure properties and methods like getRootProps and acceptedFiles to manage drag-and-drop actions. |
|
React
import { useCallback, useState } from "react"
import { useDropzone } from "react-dropzone"
import "./App.css"
export default function MyDropzone() {
const [dataURL, setDataURL] = useState(null)
const [uploadedURL, setUploadedURL] = useState(null)
const onDrop = useCallback(acceptedFiles => {
acceptedFiles.forEach(file => {
const reader = new FileReader()
reader.onabort = () => console.log("file reading was aborted")
reader.onerror = () => console.log("file reading has failed")
reader.onload = () => {
const binaryStr = reader.result
setDataURL(binaryStr)
}
reader.readAsDataURL(file)
})
}, [])
const {
getRootProps,
acceptedFiles,
getInputProps,
isDragActive,
} = useDropzone({ onDrop })
Spreading react-dropzone
props in a <div>
Spread the props from getRootProps() and getInputProps() onto the <div> to make it handle drag-and-drop events. |
|
Html
<div className="drop-zone" {...getRootProps()}>
<input {...getInputProps()} />
Accessing selected files
Use acceptedFiles to access the array of selected files. Try logging the first selected file with console.log to see it in action. |
|
React
const {
getRootProps,
acceptedFiles,
getInputProps,
isDragActive,
} = useDropzone({ onDrop })
const selectedFile = acceptedFiles[0]
console.log(selectedFile)
Setting state for data URL
In the onDrop function, loop through the selected files (in this example, just one file). Use the FileReader API to read the file and listen for the onload event. Once the file has been read, set the file's dataURL as a state variable to display an image preview. |
|
React
export default function MyDropzone() {
const [dataURL, setDataURL] = useState(null)
const [uploadedURL, setUploadedURL] = useState(null)
const onDrop = useCallback(acceptedFiles => {
acceptedFiles.forEach(file => {
const reader = new FileReader()
reader.onabort = () => console.log("file reading was aborted")
reader.onerror = () => console.log("file reading has failed")
reader.onload = () => {
const binaryStr = reader.result
setDataURL(binaryStr)
}
reader.readAsDataURL(file)
})
}, [])
Implementing visual feedback for drag-and-drop
Implement visual feedback by checking isDragActive , which becomes true when a file is being dragged over the drop zone. Use this state to show a message or overlay, and if dataURL is not null , display a preview of the selected image along with options to upload or cancel. The buttons displayed on the preview provide a way to either cancel the action or upload the selected image, triggering the uploadImage function. |
|
React
return (
<div className="container">
<div className="zone">
{dataURL ? (
<div className="selected">
<img src={dataURL} />
<div className="actions">
{uploadedURL ? (
<span className="uploaded-txt">Uploaded!</span>
) : (
<button
onClick={uploadImage}
className="upload-btn"
>
Upload
</button>
)}
<button
onClick={() => setDataURL(null)}
className="cancel-btn"
>
Cancel
</button>
</div>
</div>
)
<div className="drop-zone" {...getRootProps()}>
<input {...getInputProps()} />
{isDragActive ? (
<div className="drop-files">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
height="50"
width="50"
fill="currentColor"
>
<path d="M1 14.5C1 12.1716 2.22429 10.1291 4.06426 8.9812C4.56469 5.044 7.92686 2 12 2C16.0731 2 19.4353 5.044 19.9357 8.9812C21.7757 10.1291 23 12.1716 23 14.5C23 17.9216 20.3562 20.7257 17 20.9811L7 21C3.64378 20.7257 1 17.9216 1 14.5ZM16.8483 18.9868C19.1817 18.8093 21 16.8561 21 14.5C21 12.927 20.1884 11.4962 18.8771 10.6781L18.0714 10.1754L17.9517 9.23338C17.5735 6.25803 15.0288 4 12 4C8.97116 4 6.42647 6.25803 6.0483 9.23338L5.92856 10.1754L5.12288 10.6781C3.81156 11.4962 3 12.927 3 14.5C3 16.8561 4.81833 18.8093 7.1517 18.9868L7.325 19H16.675L16.8483 18.9868ZM13 13V17H11V13H8L12 8L16 13H13Z"></path>
</svg>
</div>
) : (
<div className="drag-files">
Drop your files here or click to browse
</div>
)}
</div>
)}
</div>
Setting Up Cloudinary for file uploads
To upload files to Cloudinary, you can use various methods. This tutorial shows how to use the upload endpoint to perform an unsigned upload for testing purposes, though signed uploads are recommended for production. Get your API key and save your credentials in a .env file. Then, create an unsigned upload preset. |
|
Creating the uploadImage function
Create an uploadImage function that uploads the file to Cloudinary using the provided API endpoint and upload preset. After uploading, store the returned URL and update the state with the response. |
|
React
const uploadImage = async () => {
let formData = new FormData()
formData.append("file", selectedFile)
formData.append("upload_preset", import.meta.env.VITE_CLOUDINARY_UPLOAD_PRESET)
formData.append("api_key", import.meta.env.VITE_CLOUDINARY_API_KEY)
await fetch(`https://api.cloudinary.com/v1_1/${import.meta.env.VITE_CLOUDINARY_CLOUD_NAME}/image/upload`, {
method: "POST",
body: formData,
})
.then(r => {
return r.json()
})
.then(data => {
setUploadedURL(data.url)
})
}
Displaying the uploaded file
After a successful upload, update the state with the public URL from the Cloudinary response and display the uploaded image in your application. | |
React
{uploadedURL && (
<a target="_blank" href={uploadedURL}>
<span className="uploaded-url">{uploadedURL}</span>
</a>
)}
Testing drag-and-drop functionality
Test your drag-and-drop functionality with Cloudinary integration. Drag a file into the drop zone, preview it, and then upload it to Cloudinary. Once uploaded, the file’s public URL is displayed, confirming successful integration. | |
Keep learning
Related topics
- Read our Upload widget guide and reference to find out about another useful way to upload in React.
- Check out some React sample projects that can be useful to you when creating your own app.
- Take a look at our React SDK to learn how to transform your images and videos.
- Watch more Dev Hints videos on the Cloudinary YouTube channel.
If you like this, you might also like...
Check out the Cloudinary Academy for free self-paced Cloudinary courses on a variety of developer or DAM topics, or register for formal instructor-led courses, either virtual or on-site.
✖️