React Hooks File Upload example with Axios & Progress Bar

In this React tutorial, I will show you way to build React Hooks File Upload example using Axios and Multipart File for making HTTP requests, Bootstrap for progress bar and display list of files’ information (with download url).

More Practice:
React Typescript File Upload example
Drag and Drop File Upload with React Hooks example
React Image Upload with Preview
React File Upload/Download example with Spring Boot Rest Api
React Hooks CRUD example with Axios and Web API
React Form Validation with Hooks example
React Hooks: JWT Authentication (without Redux) example
React + Redux: JWT Authentication example
React Custom Hook

Serverless:
React Hooks + Firebase Realtime Database: CRUD App
React Hooks + Firestore example: CRUD app

Multiple Files Upload:
React Hooks Multiple File upload example with Axios & Progress Bar

Using React Components instead:
React File Upload with Axios and Progress Bar to Rest API


React Hooks File Upload Overview

Weโ€™re gonna create a React Hooks File Upload application in that user can:

  • see the upload process (percentage) with progress bar
  • view all uploaded files
  • download link to file when clicking on the file name

react-hooks-file-upload-axios-example-progress-bar

Technology

  • React 18/17/16
  • Axios 0.27.2
  • Bootstrap 4

Web API for File Upload & Storage

Here are APIs that we will use Axios to make HTTP requests:

Methods Urls Actions
POST /upload upload a File
GET /files get 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 MongoDB example
Node.js Express File Upload to Google Cloud Storage example
Spring Boot Multipart File upload (to static folder) example

Project Structure

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

react-hooks-file-upload-progress-axios-project-structure

Let me explain it briefly.

FileUploadService provides functions to save File and get Files using Axios.
FileUpload contains file upload form, progress bar, display of list files.
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 Hooks File Upload Project

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

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


public
src
components
FileUpload.js
services
FileUploadService.js
App.css
App.js
index.js
package.json

Import Bootstrap to React Hooks File Upload App

Run command: npm install [email protected].
Or: yarn add [email protected]

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

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

function App() {
  return (
    ...
  );
}

export default App;

Initialize Axios for React HTTP Client

Let’s install axios with command: npm install [email protected].
Or: yarn add [email protected]

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/FileUploadService.js

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

const upload = (file, onUploadProgress) => {
  let formData = new FormData();

  formData.append("file", file);

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

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

export default {
  upload,
  getFiles,
};

– 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 Page for Upload Files

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

First we create a React template with React Hooks (useState, useEffect) and import FileUploadService:

components/FileUpload.js

import React, { useState, useEffect } from "react";
import UploadService from "../services/FileUploadService";

const UploadFiles = () => {
  
  return (
    
  );
};

export default UploadFiles;

Then we define the state using React Hooks:

const UploadFiles = () => {

  const [selectedFiles, setSelectedFiles] = useState(undefined);
  const [currentFile, setCurrentFile] = useState(undefined);
  const [progress, setProgress] = useState(0);
  const [message, setMessage] = useState("");

  const [fileInfos, setFileInfos] = useState([]);

  ...
}

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

const UploadFiles = () => {
  ...
  const selectFile = (event) => {
    setSelectedFiles(event.target.files);
  };

  ...
}

We use selectedFiles for accessing current File as the first Item. Then we call UploadService.upload() method on the currentFile with a callback. So create following upload() method:

const UploadFiles = () => {
  ...

  const upload = () => {
    let currentFile = selectedFiles[0];

    setProgress(0);
    setCurrentFile(currentFile);

    UploadService.upload(currentFile, (event) => {
      setProgress(Math.round((100 * event.loaded) / event.total));
    })
      .then((response) => {
        setMessage(response.data.message);
        return UploadService.getFiles();
      })
      .then((files) => {
        setFileInfos(files.data);
      })
      .catch(() => {
        setProgress(0);
        setMessage("Could not upload the file!");
        setCurrentFile(undefined);
      });

    setSelectedFiles(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 files’ information and assign the result to fileInfos state, which is an array of {name, url} objects.

We also need to do this work in the Effect Hook useEffect() method which serves the same purpose as componentDidMount():

const UploadFiles = () => {
  ...
  useEffect(() => {
    UploadService.getFiles().then((response) => {
      setFileInfos(response.data);
    });
  }, []);

  ...
}

Now we return the Upload File UI. Add the following code inside return() block:

const UploadFiles = () => {
  ...
  return (
    <div>
      {currentFile && (
        <div className="progress">
          <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>
      )}

      <label className="btn btn-default">
        <input type="file" onChange={selectFile} />
      </label>

      <button
        className="btn btn-success"
        disabled={!selectedFiles}
        onClick={upload}
      >
        Upload
      </button>

      <div className="alert alert-light" role="alert">
        {message}
      </div>

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

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

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

Don’t forget to export the function component:

const UploadFiles = () => {
  ...
}

export default UploadFiles;

You can simplify import statement with:
Absolute Import in React

Add Files Upload Component to App Component

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

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

import FileUpload from "./components/FileUpload";

function App() {
  return (
    <div className="container" style={{ width: "600px" }}>
      <div className="my-3">
        <h3>bezkoder.com</h3>
        <h4>React Hooks File Upload</h4>
      </div>

      <FileUpload />
    </div>
  );
}

export default App;

Configure Port for React File Upload App

Because most of HTTP Server use CORS configuration that accepts resource sharing restricted to some sites or ports, and if you use the Project in 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 MongoDB 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 App with command: npm start.
Or: yarn start.

Open Browser with url http://localhost:8081/ and check the result.

Conclusion

Today we’re learned how to build a React Hooks application for upload Files using Axios, Bootstrap with Progress Bar. We also provide the ability to show list of files, upload progress percentage, and to download file from the server.

For Multiple Files Upload like this:

react-hooks-multiple-files-upload-example

Please visit:
React Hooks Multiple File upload example with Axios & Progress Bar

Using React Components instead:
React File Upload with Axios and Progress Bar to Rest API

Happy Learning! See you again.

Further Reading

Fullstack:
React + Spring Boot + MySQL: CRUD example
React + Spring Boot + PostgreSQL: CRUD example
React + Spring Boot + MongoDB: CRUD example
React + Node.js + Express + MySQL: CRUD example
React + Node.js + Express + PostgreSQL example
React Redux + Node.js + Express + MySQL: CRUD example
React + Node.js + Express + MongoDB example
React + Django + Rest Framework example

Serverless:
React Hooks + Firebase Realtime Database: CRUD App
React Hooks + Firestore example: CRUD app

Source Code

You can find the complete source code for this tutorial at Github.

Typescript version: React Typescript File Upload example
Drag-Drop instead: Drag and Drop File Upload with React Hooks example
Uploading Image: React.js Image Upload with Preview

15 thoughts to “React Hooks File Upload example with Axios & Progress Bar”

  1. Thank you for the tutorial, I’ve noticed the progress is not updated after the first upload.

    Maybe I did something wrong, or maybe it is required to add a little code in the useEffect to update the component ?

    1. Hi, maybe your file is small, so the progress is fast and you cannot see the increment of percentage. You can try with a larger file.

  2. Very good tutorial ! Thanks !
    I tried the dual with ‘Spring Boot U/Dload File to/from database example’ and it works well ๐Ÿ™‚
    Do you have some dual tutorials (client/server) for websocket chat with spring boot & react hooks ?

  3. Tutorial says axios tutorial and i see you configure it at the start, but you never use axios. You use some other http library why si that?

    1. Hi, first I export axios object from http-common.js:

      import axios from "axios";
      
      export default axios.create(...);
      

      Then in FileUploadService.js, I import and use it as http:

      import http from "../http-common";
  4. Thanks for this tutorial. However when I am trying to run the project, I am always getting error as “Could not upload the file!”

    When i check the console it saya “xhr.js:178 POST http://localhost:8080/upload net::ERR_CONNECTION_REFUSED”

    Am I doing something wrong here? Please suggest

    1. Hi, the code should be run with a server, Spring Boot App (mentioned in this tutorial) for example.
      Or you can write your own backend with APIs like this.

    2. Maybe file size is bigger than 10MB, I had the same issue with error :
      Failed to parse multipart servlet request; nested exception is java.lang.IllegalStateException: io.undertow.server.RequestTooBigException: UT000020: Connection terminated as request was larger than 10485760]

    1. Hi, just run both of them, then open your browser with url: http://localhost:8081.

Comments are closed to reduce spam. If you have any question, please send me an email.