Drag and Drop File Upload in React & Laravel — Step-by-Step Tutorial Part 2
In the second part of this tutorial, we will move to the frontend. First, we will create the upload component, and next, we will upload the file to our backend and save it in our database.
Install the Packages
First, let's install the packages we need. We will install Bootstrap 5 and axios using the command:
npm i axios bootstrap@5.3.8
Now, let's move to the main.js file and import and use Bootstrap 5.
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import 'bootstrap/dist/css/bootstrap.min.css'
import './index.css'
import App from './App.jsx'
createRoot(document.getElementById('root')).render(
<StrictMode>
<App />
</StrictMode>,
)
Create the Upload Component
Inside your src folder, create a new file and call it Upload.jsx, and add the following code inside:
import React, { useRef, useState } from "react"
import axios from 'axios'
export default function Upload() {
const [imageUrl, setImageUrl] = useState(null)
const [file, setFile] = useState(null)
const inputRef = useRef(null)
// Trigger file input when dropzone is clicked
const handleClick = () => {
inputRef.current.click();
}
// Event handler for file drop
const handleDrop = (e) => {
e.preventDefault()
handleFile(e.dataTransfer.files[0])
}
// Event handler for file input change (for click to select)
const handleFileSelect = (e) => {
handleFile(e.target.files[0])
// This ensures that even if you choose the same
// file multiple times, the component will recognize the selection
// and proceed with the upload process.
e.target.value = ''
}
// Handle file drop / select
const handleFile = (file) => file && displayImage(file)
// Displays the image preview from a file object
const displayImage = (file) => {
const reader = new FileReader()
reader.onload = () => setImageUrl(reader.result)
reader.readAsDataURL(file)
setFile(file)
}
// Upload image
const uploadImage = async (e) => {
e.preventDefault()
// Set the form data
const formData = new FormData()
formData.append('file', file)
// Send the request
try {
const response = await axios.post('http://127.0.0.1:8001/api/upload', formData)
console.log(response.data)
} catch (error) {
console.error(error)
}
}
return (
<div className="row my-4">
<div className="col-md-6 mx-auto">
<div className="card">
<div className="card-header text-center bg-white">
<h3 className="mt-2">Upload Your Image</h3>
</div>
<div className="card-body">
<form onSubmit={(e) => uploadImage(e)}>
<div
id="dropzone"
onDrop={handleDrop}
onDragOver={(e) => e.preventDefault()}
onDragLeave={(e) => e.preventDefault()}
onClick={handleClick}
className="rounded p-5 text-center"
>
<label htmlFor="file-input" className="form-label mb-2">
Drag & Drop Your Image Here or Click to Select
</label>
<input
type="file"
name="image"
id="file-input"
className="form-control"
accept="image/*"
onChange={handleFileSelect}
ref={inputRef}
hidden
/>
{
imageUrl && <img src={imageUrl} alt="Preview" className="img-fluid mt-3 rounded shadow-sm" style={{maxHeight: '200px'}} />
}
</div>
<button type="submit" className="btn btn-primary w-100 mt-3"
onClick={(e) => uploadImage(e)}
disabled={!file}
>
Upload Image
</button>
</form>
</div>
</div>
</div>
</div>
)
}
Add Some CSS Styles to the Upload Component
Inside the index.css file, let's add some CSS styles to our upload component.
/* dropzone */
#dropzone {
background: #f8f9fa;
border: 2px dashed #666;
cursor: pointer;
transition: background 0.3s, border-color 0.3s;
}
#dropzone label {
cursor: pointer;
}
#dropzone:hover {
background-color: #f0eeee;
border-color: #888;
}
Use It in Your App Component
Inside the App.jsx file, let's import and use the Upload Component.
import Upload from "./Upload"
function App() {
return (
<Upload />
)
}
export default App