Uploading multiple images is a common task when building web applications.
In this blog post, we will go through the steps to upload multiple images to a backend API using React.js
This blog post is the part of our will be divided into 2 parts
Part 1 : Backend API whit Rails 7
- Github link : multiple-image-uploads-api
- Blog post : Part 1
Part 2 : Frontend with React.js
- Github link : multiple-image-uploads-client
- First create a new react app bootstraped with vitejs
npm create vite@latest multiple-image-uploads-client
- Select
React
click enter, thenjavascript
as shown on the images bellow
React | JavaScript |
---|---|
- Navigate to the project and install all dependencies
cd multiple-image-uploads-client
npm install
- Go back to the backend project and run the rails server again
rails server
- Now open the frontend in your prefered code editor and run server as well
npm run dev
At this point you should have 2 servers running on 2 differents ports.
The backend on http://127.0.0.1:3000/ and the frontend on http://127.0.0.1:5173/
- Clean up the
App.jsx
file in undersrc/
directory and make it look like the following :
import { useState } from "react";
import "./App.css";
function App() {
return (
<div className="App">
Upload multiple images To Rails 7 API - Active_storage : Part 1
</div>
);
}
export default App;
- At this point we can start implementing all neccessary features.
copy and paste the following code into
App.jsx
file then read the explaination after.
import { useState, useRef } from "react";
import "./App.css";
const API_URL = "http://127.0.0.1:3000";
function App() {
const [images, setImages] = useState([]);
const imagesRef = useRef(null);
const postToGet = useRef("");
const handleUpload = (e) => {
e.preventDefault();
const formData = new FormData();
formData.append("post[title]", Date.now().toString());
if (imagesRef.current && imagesRef.current.files) {
for (let i = 0; i < imagesRef.current.files.length; i++) {
formData.append("post[images][]", imagesRef.current.files[i]);
}
postData(formData);
}
};
const postData = (formData) => {
fetch(`${API_URL}/posts`, {
method: "POST",
body: formData,
})
.then((res) => res.json())
.then((data) => {
console.log(data);
getImages(data.id);
})
.catch((err) => console.log(err));
};
const getImages = (postId) => {
fetch(`${API_URL}/posts/${postId}`)
.then((res) => res.json())
.then((data) => {
console.log(data);
setImages(data.images || []);
})
.catch((err) => console.log(err));
};
return (
<div className="App">
{/* upload form */}
<form style={{ margin: "10px" }}>
<input
type="file"
name="image"
multiple
ref={imagesRef}
style={{ margin: "5px" }}
/>
<button type="button" onClick={handleUpload}>
Submit
</button>
</form>
{/* Get images button */}
<div style={{ margin: "10px" }}>
<input
type="number"
ref={postToGet}
placeholder="ID to retrieve"
style={{ margin: "5px" }}
/>
<button onClick={() => getImages(postToGet.current.value)}>
Get Images
</button>
</div>
{/* images */}
<div className="images">
{images.map((image, index) => (
<img
key={index}
src={image}
alt="uploaded"
style={{ width: "200px", height: "200px", margin: "10px" }}
/>
))}
</div>
</div>
);
}
export default App;
Explainations :
This is a React application that allows users to upload images and retrieve previously uploaded images by making API requests to a local server at http://127.0.0.1:3000
.
The useState
and useRef
hooks are imported from the react module at the beginning of the file.
The App
function is defined as the main component of the application. Inside the component, the state variable images
is initialized to an empty array and the ref variable imagesRef
is initialized to null
. Another ref variable postToGet
is initialized to an empty string.
The handleUpload
function is defined to handle the form submission when the user uploads an image. The function first prevents the default form submission behavior by calling preventDefault()
on the event object passed in as an argument. It then creates a new FormData
object and appends the title of the post, which is set to the current timestamp as a string. The function then loops through the files
property of the imagesRef
ref variable and appends each file to the FormData
object. Finally, the postData
function is called with the FormData
object as an argument.
The postData
function sends a POST request to the server using the fetch
API. It includes the formData
object as the body of the request and sets the content type to multipart/form-data
. When the response is received, it is converted to JSON using the json()
method and the resulting data is logged to the console. The getImages
function is then called with the id
of the newly created post as an argument. If there is an error, it is caught and logged to the console.
The getImages
function sends a GET request to the server to retrieve the images associated with a specific post ID. When the response is received, it is converted to JSON using the json()
method and the resulting data is logged to the console. If the response includes an images
property, the state variable images
is updated with the array of images. If there is an error, it is caught and logged to the console.
The return
statement of the App
function includes a form for uploading images, a form for retrieving images by post ID, and a section for displaying the images. The form for uploading images includes an input
element of type file
with the imagesRef
ref variable attached to it, and a button
element with an onClick
event listener attached to it that calls the handleUpload
function. The form for retrieving images includes an input
element of type number
with the postToGet
ref variable attached to it, and a button
element with an onClick
event listener attached to it that calls the getImages
function with the value of the postToGet
ref variable as an argument. The section for displaying images includes an array of img
elements, each with a unique key
attribute, a src
attribute set to the URL of the image, and styling to set the dimensions and margin. The images
state variable is mapped over to create the array of img elements.
Finally, the App
component is exported as the default export of the module, allowing it to be used in other parts of the application.
If you have any suggestions, please feel free to leave a comment and connect with me so that we can implement them together through pair-programming. Don't forget to follow, like, and share.
Top comments (0)