To upload the file you always need a server-side application. The file will be uploaded to the server-side and its name will be stored in the database. At the client-side application, you required the file that will be sent to the server-side using the API. You can implement File upload in React JS. For the file upload in React JS, I will use the Laravel 8 RESTful API. On the client-side, we will create the form to select the file. Then using the API, we will send the file to be upload at the server-side. For the API handling, I will be using the Axios library in React JS. In the last post of React JS, I have already shown you the use of Axios in React for API Request handling. Basically, we will check the Image(s) upload in React JS using Laravel API.
At the server-side, we will validate the file using the mime type and size. So, let’s start this post for React Axios file upload. Firstly, we will create a RESTful API in Laravel 8.
Prerequisites
Before moving ahead to this post, you have to make sure to have the below configuration in your system.
- PHP >= 7.3
- MySQL (version > 5)
- Apache/Nginx Server
- VS Code Editor
- Composer
- Postman/Insomnia (For API Testing)
Let’s start by opening the terminal for creating the project in Laravel 8.
Create Project in Laravel 8
Here, we will go with composer for creating the project. Hence, you need to open the terminal or command prompt. Now, hit the below command inside it.
composer create-project --prefer-dist laravel/laravel react-api
The command will start the installation of Laravel 8 inside a new folder.
After creating the project, let’s run it and check the result in the browser.
Now, let’s create and configure a database for this project.
How to Generate PDF File in Laravel 8 Using DOM PDF
Create and Configure Database in Laravel 8
After file upload in React JS, the file will be moved to the specified folder on the server-side. Also, the file name will be stored in the database table. Hence, you required to have a database connected with the Laravel 8 project.
CREATE DATABASE laravel_react_api;
After creating the database in MySQL, let’s configure it to the Laravel 8 project.
So, just open the .env file and under the database section, just put the database credentials.
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel_react_api
DB_USERNAME=root
DB_PASSWORD=root
Now, you are good to go for creating the API for React file upload.
RESTful APIs For Todo App Using Passport Auth in Laravel 8
Create Model, Migration and Controller in Laravel 8
Here, we will create model, migration and a controller file. So, it is possible to create all in one command.
php artisan make:model Image -mc
This command will create a model, a migration and a controller respectively.
After creating the migration file, let’s open it and add the fields for storing file name to the table.
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateImagesTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('images', function (Blueprint $table) {
$table->id();
$table->string('image_name')->nullable();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('images');
}
}
In the above migration file, I have added one field. The migration file needs to be migrated into the database.
php artisan migrate
After the migration, it will generate the specified tables into the database.
In the next step, you need to add the fillable property inside the created model file.
How to Implement Invisible reCAPTCHA in Laravel 8
Add Fillable Data in Model
Before saving the data into the table through the Eloquent, you have to specify the attribute. Hence, just navigate to the Image.php inside the app/Models directory of the project. Then put the below code.
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Image extends Model
{
use HasFactory;
protected $fillable = [
"image_name"
];
}
Now, you are good to go for creating the API for React Image upload. So, let’s move to the controller file.
Create Authentication in Laravel 8 Using Laravel Breeze
Image Upload in Laravel 8
You created a controller named ImageController.php. Now, just open it, and write the functionality for image upload at the server-side.
<?php
namespace App\Http\Controllers;
use App\Models\Image;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
class ImageController extends Controller
{
/**
* Fetch images
* @param NA
* @return JSON response
*/
public function index() {
$images = Image::all();
return response()->json(["status" => "success", "count" => count($images), "data" => $images]);
}
/**
* Upload Image
* @param $request
* @return JSON response
*/
public function upload(Request $request) {
$imagesName = [];
$response = [];
$validator = Validator::make($request->all(),
[
'images' => 'required',
'images.*' => 'required|image|mimes:jpeg,png,jpg,gif,svg|max:2048'
]
);
if($validator->fails()) {
return response()->json(["status" => "failed", "message" => "Validation error", "errors" => $validator->errors()]);
}
if($request->has('images')) {
foreach($request->file('images') as $image) {
$filename = time().rand(3, 9). '.'.$image->getClientOriginalExtension();
$image->move('uploads/', $filename);
Image::create([
'image_name' => $filename
]);
}
$response["status"] = "successs";
$response["message"] = "Success! image(s) uploaded";
}
else {
$response["status"] = "failed";
$response["message"] = "Failed! image(s) not uploaded";
}
return response()->json($response);
}
}
In the above controller, I have created two functions. One for fetching all uploaded images from the table. The second function is for uploading image(s). I have validated the image using the mime type validation rule.
Next, you need to have the routes specific for these two functions.
User Authentication in Laravel 8 Using UI Auth Package
Create API Routes
For creating the API routes, you will need to navigate to the routes/api.php file.
Route::get('images', [ImageController::class, 'index'])->name('images');
Route::post('images', [ImageController::class, 'upload'])->name('images');
After creating the routes, let’s check the API into the Postman.
Check API Results in Postman
For the API testing, I will use Postman here. We have the endpoints-
Request Type: GET
Endpoint: http://localhost:8000/api/images
Request Type: POST
Endpoint: http://localhost:8000/api/images
Data: Body->form-data: images[]
Now, check the endpoints one by one. Let’s try with uploading images. Here, I have implemented the multiple images functionality so if there has more than one image then it will be uploaded too.
If the image is not selected then it will throw the required validation error message.
Now, check by selecting a different mime type rather than an image. Here, you can see as per the validation rule, it is asking for the image.
After selecting the proper image, you will have the success message as showing below.
Also, you can check the database table after inserting the image.
Through the second endpoint, you will get the uploaded images name. So, we will show the uploaded images in our React file upload application.
That’s it for the API part. Now, let’s create the React application for File upload.
Dynamic Email Configuration in Laravel 8 For Sending Email
Create React App For File Upload
For creating the React app, you must have the node.js. So, open the terminal and hit the below command.
npx create-react-app blog
Above command will start creating a React application.
After creating the app, let’s open it to editor and run it to the browser.
cd blog
npm start
Form Handling in React JS With Validation Using React State
Install Axios in React JS
For file upload in React JS we will use Axios library. Hence, it will require to be installed inside the React application.
npm i axios
After finishing the installation, we will install the Bootstrap for creating a form component.
Install Bootstrap in React JS
For installing Bootstrap in React JS, you need to run the below command.
npm i bootstrap
Now, you are ready with Axios library and Bootstrap. But, one more library may be required to create any route. So, let’s install it.
Brief Overview of React Routing Using React Router DOM
Install React Router DOM
For creating a route, I will be installing the react-router-dom package. You can install it using the below command.
npm i react-router-dom
Now, let’s create components for Image upload and fetching the uploaded images.
Create Components in React JS For File Upload
We will create two components here. The components are as follows-
- ImageUpload.js – For Uploading image/file
- Images.js – For getting uploaded images from API
In this post, we will see the single and multiple image upload. So, after creating the components, let’s implement the functionality of single file upload first.
Create a Todo App in React Using Laravel 8 RESTful APIs
Upload Single Image/File in React JS
Open the ImageUpload.js component and put the below code there.
import React, { Component } from 'react';
import axios from 'axios';
import Images from "./Images";
export default class ImageUpload extends Component {
constructor(props) {
super(props);
this.state = {
image: "",
responseMsg: {
status: "",
message: "",
error: "",
},
};
}
// image onchange hander
handleChange = (e) => {
this.setState({
image: e.target.files[0]
})
}
// submit handler
submitHandler = (e) => {
e.preventDefault();
const data = new FormData()
data.append('images', this.state.image)
axios.post("http://localhost:8000/api/images", data)
.then((response) => {
if (response.status === 200) {
this.setState({
responseMsg: {
status: response.data.status,
message: response.data.message,
},
});
setTimeout(() => {
this.setState({
image: "",
responseMsg: "",
});
}, 2000);
document.querySelector("#imageForm").reset();
// getting uploaded images
this.refs.child.getImages();
}
})
.catch((error) => {
console.error(error);
});
}
render() {
return (
<div className="container py-5">
<div className="row">
<div className="col-xl-6 col-lg-8 col-md-8 col-sm-12 m-auto">
<form onSubmit={this.submitHandler} encType="multipart/form-data" id="imageForm">
<div className="card shadow">
{this.state.responseMsg.status === "successs" ? (
<div className="alert alert-success">
{this.state.responseMsg.message}
</div>
) : this.state.responseMsg.status === "failed" ? (
<div className="alert alert-danger">
{this.state.responseMsg.message}
</div>
) : (
""
)}
<div className="card-header">
<h4 className="card-title fw-bold">
Upload Image in React Using Laravel 8 API
</h4>
</div>
<div className="card-body">
<div className="form-group py-2">
<label htmlFor="images">Images</label>
<input
type="file"
name="image"
onChange={this.handleChange}
className="form-control"
/>
<span className="text-danger">
{this.state.responseMsg.error}
</span>
</div>
</div>
<div className="card-footer">
<button type="submit" className="btn btn-success">
Upload
</button>
</div>
</div>
</form>
</div>
</div>
<Images ref="child" />
</div>
);
}
}
- In the above code, I have created a form with an input type file. For the input file, I have created an onChange event.
- I have read the file available at 0 index and set this to the state.
- Then created the form submit handler and inside this, I have created the API call in React with Axios for file upload.
- For submitting the file, I have used FormData(). Then appended the file into the form data object and passed it to the API.
React Login and Registration App Using Laravel 7 API
Create Route in React JS
For creating the route, I have used React Router DOM. We already installed it in our project. So, I have imported it inside the App component.
import React, { Component } from 'react';
import { Route, BrowserRouter as Router, Switch } from 'react-router-dom';
import ImageUpload from './components/ImageUpload';
class App extends Component {
render() {
return (
<Router>
<Switch>
<Route path="/upload-image" component={ ImageUpload }/>
</Switch>
</Router>
);
}
}
export default App;
Now, we can run the React application to see the result.
Check Form For Image Upload
I have created a route in the App.js file for rendering the component through the route.
When you open the route upload-image
, you will have the below component rendered to your browser.
Get Uploaded Images in React JS
Inside the ImageUpload component, I have called the second component (Images.js) that we already created. This component will fetch the uploaded images through the API call.
So, put the below code first inside this component.
import React, { Component } from "react";
import axios from "axios";
export default class Images extends Component {
constructor(props) {
super(props);
this.state = {
images: [],
};
}
componentDidMount() {
this.getImages();
}
getImages = () => {
axios
.get("http://localhost:8000/api/images")
.then((response) => {
if (response.status === 200) {
this.setState({
images: response.data.data,
});
console.log(response.data);
}
})
.catch((error) => {
console.error(error);
});
};
render() {
return (
<div className="container pt-4">
<div className="row">
<div className="col-xl-6 col-lg-8 col-md-8 col-sm-12 m-auto">
<div className="card shadow">
<div className="card-header">
<h4 className="card-title fw-bold"> Images List </h4>
</div>
<div className="card-body">
<div className="row">
{
this.state.images.length > 0 ? (
this.state.images.map((image) => (
<div className="col-xl-6 col-lg-8 col-sm-12 col-12 mt-3" key={image.id}>
<img src={ "http://localhost:8000/uploads/" + image.image_name } className="img-fluid img-bordered" width="200px"
/>
</div>
))
) : (
<h6 className="text-danger text-center">No Image Found </h6>
)
}
</div>
</div>
</div>
</div>
</div>
</div>
);
}
}
In the above component, I have created a function to get all images from the database through the Axios API. I have used GET request here. This function is called inside the componentDidMount() function. So, that when the component will invoke, the function will call and return the images.
Check Result of Single Image Upload
Try selecting image and upload it. In the response, you will get the success message as showing below. Here, I have used a simple alert of bootstrap.
So, image is uploaded and fetched immediately through the another API call. Also, it rendered into the same component.
Create a CRUD App in React.js Using Laravel 7 RESTful API
Multiple Images/Files Upload in React JS
For reading multiple images through file input, you will have to do the following steps-
- Add attribute multiple in file input
- Read the selected file through loop because the files will be in the form of array.
<input type="file" name="image" multiple onChange={this.handleChange} className="form-control" />
The onChange() handler function will look like this-
// image onchange hander
handleChange = (e) => {
const imagesArray = [];
let isValid = "";
for (let i = 0; i < e.target.files.length; i++) {
imagesArray.push(e.target.files[i]);
}
this.setState({
image: imagesArray,
});
};
This time, we will set the array of selected files in the state.
So, you have to use the same process for pushing the state array to the FormData(). Here, I have itereated the state (array of image) and appended one by one to the form data.
// submit handler
submitHandler = (e) => {
e.preventDefault();
const data = new FormData();
for (let i = 0; i < this.state.image.length; i++) {
data.append("images[]", this.state.image[i]);
}
axios.post("http://localhost:8000/api/images", data)
.then((response) => {
if (response.status === 200) {
this.setState({
responseMsg: {
status: response.data.status,
message: response.data.message,
},
});
setTimeout(() => {
this.setState({
image: "",
responseMsg: "",
});
}, 2000);
document.querySelector("#imageForm").reset();
// getting uploaded images
this.refs.child.getImages();
}
})
.catch((error) => {
console.error(error);
});
};
Now, you can select the multiple files in the input file.
Multiple Files/Images Upload Result
After selecting the multiple images, try uploading it.
In the response, you will see the images are uploaded and displayed to the Images component.
You can validate the image in React JS by creating a basic validation rule.
Validate Image at Client Side in React JS
I have created a basic validation rule for validating the file type. This function is called inside the onChange() handler of input type file. So, that when you will select the file, it will check and return the response immediately.
// file validation
fileValidate = (file) => {
if (
file.type === "image/png" ||
file.type === "image/jpg" ||
file.type === "image/jpeg"
) {
this.setState({
responseMsg: {
error: "",
},
});
return true;
} else {
this.setState({
responseMsg: {
error: "File type allowed only jpg, png, jpeg",
},
});
return false;
}
};
It will allow the file type of jpg, png, jpeg. You may add more accurate validation as per your requirement. This is just for giving you a basic idea.
The final code of ImageUpload component will become like this.
import React, { Component } from "react";
import axios from "axios";
import Images from "./Images";
export default class ImageUpload extends Component {
constructor(props) {
super(props);
this.state = {
image: "",
responseMsg: {
status: "",
message: "",
error: "",
},
};
}
// image onchange hander
handleChange = (e) => {
const imagesArray = [];
let isValid = "";
for (let i = 0; i < e.target.files.length; i++) {
isValid = this.fileValidate(e.target.files[i]);
imagesArray.push(e.target.files[i]);
}
this.setState({
image: imagesArray,
});
};
// submit handler
submitHandler = (e) => {
e.preventDefault();
const data = new FormData();
for (let i = 0; i < this.state.image.length; i++) {
data.append("images[]", this.state.image[i]);
}
axios.post("http://localhost:8000/api/images", data)
.then((response) => {
if (response.status === 200) {
this.setState({
responseMsg: {
status: response.data.status,
message: response.data.message,
},
});
setTimeout(() => {
this.setState({
image: "",
responseMsg: "",
});
}, 100000);
document.querySelector("#imageForm").reset();
// getting uploaded images
this.refs.child.getImages();
}
})
.catch((error) => {
console.error(error);
});
};
// file validation
fileValidate = (file) => {
if (
file.type === "image/png" ||
file.type === "image/jpg" ||
file.type === "image/jpeg"
) {
this.setState({
responseMsg: {
error: "",
},
});
return true;
} else {
this.setState({
responseMsg: {
error: "File type allowed only jpg, png, jpeg",
},
});
return false;
}
};
render() {
return (
<div className="container py-5">
<div className="row">
<div className="col-xl-6 col-lg-8 col-md-8 col-sm-12 m-auto">
<form onSubmit={this.submitHandler} encType="multipart/form-data" id="imageForm">
<div className="card shadow">
{this.state.responseMsg.status === "successs" ? (
<div className="alert alert-success">
{this.state.responseMsg.message}
</div>
) : this.state.responseMsg.status === "failed" ? (
<div className="alert alert-danger">
{this.state.responseMsg.message}
</div>
) : (
""
)}
<div className="card-header">
<h4 className="card-title fw-bold">
Upload Image in React Using Laravel 8 API
</h4>
</div>
<div className="card-body">
<div className="form-group py-2">
<label htmlFor="images">Images</label>
<input
type="file"
name="image"
multiple
onChange={this.handleChange}
className="form-control"
/>
<span className="text-danger">
{this.state.responseMsg.error}
</span>
</div>
</div>
<div className="card-footer">
<button type="submit" className="btn btn-success">
Upload
</button>
</div>
</div>
</form>
</div>
</div>
<Images ref="child" />
</div>
);
}
}
Conclusion
We have seen the file upload using Axios in React JS. For the API, we used Laravel 8 with the MySQL database. The Axios library is used to handle the API request. We tried single as well as multiple file upload here. Also, we created a basic validation for checking file type. So, that’s it for the React File upload using Axios. I hope you will have a clear picture after going through this post. Thank you.
Kabir says
If you do the same thing with react functional component , that will be a great help as now a days most of the beginner use functional component instead of class component
Ayshik says
local.ERROR: rand() expects exactly 2 arguments, 1 given {“exception”:”[object] (ArgumentCountError(code: 0): rand() expects exactly 2 arguments, 1 given at E:\\laravel-react-pic\\app\\Http\\Controllers\\ImageController.php:38)
[stacktrace]
Umesh Rana says
Hi Ayshik,
In ImageController, while creating the file name pass 2 arguments inside the rand() function as like rand(3, 9)