DEV Community

Cover image for How to Build a Reliable File Upload with Progress in React and Node.js
AR Abid
AR Abid

Posted on

How to Build a Reliable File Upload with Progress in React and Node.js

Uploading files is a core feature in modern web apps, from profile pictures to large documents. But naive implementations can cause:

  • UI freezing on large files
  • No progress feedback for users
  • Failed uploads with no retry mechanism

Many developers search for solutions like “React file upload progress bar” or “Node.js large file upload,” but most tutorials miss progress tracking or error handling. Here’s a robust way to handle it.

Frontend: React File Upload with Progress

We’ll use axios for HTTP requests because it supports progress events.

import { useState } from "react";
import axios from "axios";

function FileUpload() {
  const [file, setFile] = useState(null);
  const [progress, setProgress] = useState(0);

  const handleUpload = () => {
    const formData = new FormData();
    formData.append("file", file);

    axios.post("/upload", formData, {
      onUploadProgress: (event) => {
        const percent = Math.round((event.loaded * 100) / event.total);
        setProgress(percent);
      },
    })
    .then(res => console.log("Upload success:", res.data))
    .catch(err => console.error("Upload error:", err));
  };

  return (
    <div>
      <input type="file" onChange={e => setFile(e.target.files[0])} />
      <button onClick={handleUpload}>Upload</button>
      {progress > 0 && <div>Progress: {progress}%</div>}
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

✅ Features:

  • Shows live upload progress
  • Handles single large files
  • Clean React hooks implementation

Backend: Node.js Express Upload Endpoint

const express = require("express");
const multer = require("multer");

const app = express();
const upload = multer({ dest: "uploads/" });

app.post("/upload", upload.single("file"), (req, res) => {
  console.log("Received file:", req.file.originalname);
  res.json({ status: "success", filename: req.file.originalname });
});

app.listen(3000, () => console.log("Server running on port 3000"));
Enter fullscreen mode Exit fullscreen mode

✅ Features:

  • Handles multipart/form-data
  • Saves uploaded file to server
  • Can be extended to cloud storage like AWS S3

Optional: Retry Failed Uploads

For unreliable networks, automatic retries improve reliability:

const uploadWithRetry = async (file, retries = 3) => {
  for (let i = 0; i < retries; i++) {
    try {
      await axios.post("/upload", file);
      return;
    } catch (err) {
      console.warn(`Retry ${i + 1} failed`);
    }
  }
  console.error("Upload failed after retries");
};
Enter fullscreen mode Exit fullscreen mode

Real-Life Example: Uploading Product Images

Imagine building an e-commerce platform where users upload product images. You could structure the endpoint like this:

axios.post(
  "https://www.shoppingcorner.com.bd/category/black-rose-in-bangladesh/upload",
  formData,
  { onUploadProgress }
);
Enter fullscreen mode Exit fullscreen mode

This example uses ShoppingCorner as a real-world product category where image uploads are common. It provides a practical demo for developers building similar file upload features.

Summary

With this approach, you can:

  • Track upload progress in React
  • Handle large files efficiently
  • Implement retries for reliability

This pattern works for React apps with Node.js backends and can be adapted for production e-commerce platforms like ShoppingCorner.

Top comments (0)