React.js Image Upload with Preview Display example

In this tutorial, I will show you way to build React.js Image Upload and Display example (with Preview) to a Rest API. The React App uses Axios and Multipart File for making HTTP requests, Bootstrap for progress bar. You also have a display list of images’ information (with download url).

More Practice:
React Multiple Files upload example with Progress Bar
React.js CRUD example to consume Web API
React JWT Authentication (without Redux) example
React + Redux: JWT Authentication example

Material UI instead:
Material UI Image Upload example with Preview, Axios & Progress Bar

Overview

We’re gonna create a React.js Image upload with Preview example application in that user can:

  • display the preview of image before uploading
  • see the upload process (percentage) with progress bar
  • view all uploaded images
  • link to download the image when clicking on the file name

react-image-upload-with-preview-example

For multiple Images upload with preview, please visit:
React Multiple Images Upload with Preview example

react-js-multiple-image-upload-with-preview-example

Technology

  • React 16/17
  • Axios 0.21.1
  • Bootstrap 4

Rest API for File Upload & Storage

Here is the API that our React App will work with:

MethodsUrlsActions
POST/uploadupload a File
GET/filesget List of Files (name & url)
GET/files/[filename]download a File

You can find how to implement the Rest APIs Server at one of following posts:
Node.js Express File Upload Rest API example
Node.js Express File Upload to Google Cloud Storage example
Spring Boot Multipart File upload (to static folder) example

Or: Spring Boot Multipart File upload (to database) example

React App for upload/download Image with preview

After building the React project is done, the folder structure will look like this:

react-image-upload-with-preview-example-project-structure

Let me explain it briefly.

file-upload.service provides methods to save File and get Files using Axios.
image-upload.component contains upload form, image preview, progress bar, display of list of images with download url.
App.js is the container that we embed all React components.

http-common.js initializes Axios with HTTP base Url and headers.
– We configure port for our App in .env

Setup React Image Upload with Preview Project

Open cmd at the folder you want to save Project folder, run command:
npx create-react-app react-image-upload-review

After the process is done. We create additional folders and files like the following tree:


public
src
components
image-upload.component.js
services
file-upload.service.js
App.css
App.js
index.js
package.json

Import Bootstrap to React Image Upload and Display App

Run command: npm install bootstrap.

Open src/App.js and modify the code inside it as following-

import React, { Component } from "react";
import "bootstrap/dist/css/bootstrap.min.css";

class App extends Component {
  render() {
    // ...
  }
}

export default App;

Initialize Axios for React HTTP Client

Let’s install axios with command: npm install axios.
Under src folder, we create http-common.js file with following code:

import axios from "axios";

export default axios.create({
  baseURL: "http://localhost:8080",
  headers: {
    "Content-type": "application/json"
  }
});

You can change the baseURL that depends on REST APIs url that your Server configures.

Create Service for File Upload

This service will use Axios to send HTTP requests.
There are 2 functions:

  • upload(file): POST form data with a callback for tracking upload progress
  • getFiles(): GET list of Files’ information

services/file-upload.service.js

import http from "../http-common";

class FileUploadService {
  upload(file, onUploadProgress) {
    let formData = new FormData();

    formData.append("file", file);

    return http.post("/upload", formData, {
      headers: {
        "Content-Type": "multipart/form-data",
      },
      onUploadProgress,
    });
  }

  getFiles() {
    return http.get("/files");
  }
}

export default new FileUploadService();

– First we import Axios as http from http-common.js.

– Inside upload() method, we use FormData to store key-value pairs. It helps to build an object which corresponds to HTML form using append() method.

– We pass onUploadProgress to exposes progress events. This progress event are expensive (change detection for each event), so you should only use when you want to monitor it.

– We call Axios post() to send an HTTP POST for uploading a File to Rest APIs Server and get() method for HTTP GET request to retrieve all stored files.

Create Component for Upload Images

Let’s create a Image Upload UI with Preview, Progress Bar, Card, Button and Message.

First we create a React component template and import FileUploadService:

components/upload-files.component.js

import React, { Component } from "react";
import UploadService from "../services/file-upload.service";

export default class UploadImages extends Component {
  constructor(props) {

  }

  render() {

  }
}

Then we define the state inside constructor() method:

export default class UploadImages extends Component {
  constructor(props) {
    super(props);
    ...

    this.state = {
      currentFile: undefined,
      previewImage: undefined,
      progress: 0,
      message: "",

      imageInfos: [],
    };
  }
}

Next we define selectFile() method which helps us to get the selected Files from <input type="file" > element later.

export default class UploadImages extends Component {
  ...
  selectFile(event) {
    this.setState({
      currentFile: event.target.files[0],
      previewImage: URL.createObjectURL(event.target.files[0]),
      progress: 0,
      message: ""
    });
  }

We use event.target.files[0] for accessing current File as the first Item.

We’re gonna use URL.createObjectURL() static method to get the image preview URL as previewImage. This method produces a DOMString including a URL describing the object provided in the parameter. The URL life is tied to the document in the window on which it was created.

We call UploadService.upload() method on the currentFile with a callback. So create following upload() method:

export default class UploadImages extends Component {
  ...
  upload() {
    this.setState({
      progress: 0,
    });

    UploadService.upload(this.state.currentFile, (event) => {
      this.setState({
        progress: Math.round((100 * event.loaded) / event.total),
      });
    })
      .then((response) => {
        this.setState({
          message: response.data.message,
        });
        return UploadService.getFiles();
      })
      .then((files) => {
        this.setState({
          imageInfos: files.data,
        });
      })
      .catch((err) => {
        this.setState({
          progress: 0,
          message: "Could not upload the image!",
          currentFile: undefined,
        });
      });
  }

The progress will be calculated basing on event.loaded and event.total.
If the transmission is done, we call UploadService.getFiles() to get the images’ information and assign the result to imageInfos state, which is an array of {name, url} objects.

We also need to do this work in componentDidMount() method:

export default class UploadImages extends Component {
  ...
  componentDidMount() {
    UploadService.getFiles().then((response) => {
      this.setState({
        imageInfos: response.data,
      });
    });
  }

Now we implement the render function of the Upload File UI. Add the following code inside render():

export default class UploadImages extends Component {
  ...
  render() {
    const {
      currentFile,
      previewImage,
      progress,
      message,
      imageInfos,
    } = this.state;

    return (
      <div>
        <div className="row">
          <div className="col-8">
            <label className="btn btn-default p-0">
              <input type="file" accept="image/*" onChange={this.selectFile} />
            </label>
          </div>

          <div className="col-4">
            <button
              className="btn btn-success btn-sm"
              disabled={!currentFile}
              onClick={this.upload}
            >
              Upload
            </button>
          </div>
        </div>

        {currentFile && (
          <div className="progress my-3">
            <div
              className="progress-bar progress-bar-info progress-bar-striped"
              role="progressbar"
              aria-valuenow={progress}
              aria-valuemin="0"
              aria-valuemax="100"
              style={{ width: progress + "%" }}
            >
              {progress}%
            </div>
          </div>
        )}

        {previewImage && (
          <div>
            <img className="preview" src={previewImage} alt="" />
          </div>
        )}

        {message && (
          <div className="alert alert-secondary mt-3" role="alert">
            {message}
          </div> 
        )}

        <div className="card mt-3">
          <div className="card-header">List of Files</div>
          <ul className="list-group list-group-flush">
            {imageInfos &&
              imageInfos.map((img, index) => (
                <li className="list-group-item" key={index}>
                  <a href={img.url}>{img.name}</a>
                </li>
              ))}
          </ul>
        </div>
      </div>
    );
  }
}

We allow only image format, so the input element will have accept="image/*" attribute.

In the code above, we use Bootstrap Progress Bar:

  • .progress as a wrapper
  • inner .progress-bar to indicate the progress
  • .progress-bar requires style to set the width by percentage
  • .progress-bar also requires role and some aria attributes to make it accessible
  • label of the progress bar is the text within it

The preview of uploading image is shown: <img className="preview" src={previewImage} alt="" />

To display List of uploaded images, we iterate over imageInfos array using map() function. On each file item, we use file.url as href attribute and file.name for showing text.

Add Image Upload Component to App Component

Open App.js, import and embed the UploadImages Component tag.

import React from "react";
import "./App.css";
import "bootstrap/dist/css/bootstrap.min.css";

import UploadImages from "./components/image-upload.component";

function App() {
  return (
    <div className="container">
      <h3>bezkoder.com</h3>
      <h4>React Image Upload with Preview</h4>

      <div className="content">
        <UploadImages />
      </div>
    </div>
  );
}

export default App;

App.css

.container{
  width: 600px !important;
  margin: 20px;
}

.content {
  margin: 20px 0;
}

.preview {
  max-width: 200px;
}

Configure Port for React File Upload App

Because most of HTTP Server use CORS configuration that accepts resource sharing retricted to some sites or ports, and if you use the Project in this post or this post for making Server, you need to configure port for our App.

In project folder, create .env file with following content:

PORT=8081

So our app will run at port 8081.

Run the App

You can find how to implement the Rest APIs Server at one of following posts:
Node.js Express File Upload Rest API example
Node.js Express File Upload to Google Cloud Storage example
Spring Boot Multipart File upload (to static folder) example

Or: Spring Boot Multipart File upload (to database) example

Run this React File Upload Axios: npm start.
Open Browser with url http://localhost:8081/ and check the result.

Further Reading

Conclusion

Today we’re learned how to build an example for Image upload and display (with Preview) using React.js and Axios. We also provide the ability to show preview, list of images, upload progress bar using Bootstrap, and to download image from the server.

Happy Learning! See you again.

If you want to upload multiple images at once like this:

react-js-multiple-image-upload-with-preview-example

You can find the instruction here:
React Multiple Images Upload with Preview example

Or using Material UI instead:
Material UI Image Upload example with Preview, Axios & Progress Bar

material-ui-image-upload-preview-react-example

Source Code

The source code for the React Client is uploaded to Github.

6 thoughts to “React.js Image Upload with Preview Display example”

  1. Hello! This is my first visit to your blog but I think this programming website is one of the best! Clear and comprehensive tutorial.

  2. Hi. thanks for this tutorial. I download the projet from github and when I try to upload I get this message : Could not upload the image! . I’ve check in the console and I get this messsage :Uncaught (in promise) Error: Request failed with status code 404. I don’t know if I have to create a folder ‘upload/’. thanks.

Leave a Reply

Your email address will not be published. Required fields are marked *