useUpload

Overview

useUpload is a lightweight React hook that lets you upload files directly from the browser using presigned URLs, with built-in progress tracking and cancellation support.

It is ideal for uploading large files to services like S3, Cloudflare R2, or GCS without proxying files through your backend.


Installation

npm install upload-with-progress

Basic Usage

import React from "react";
import { useUpload } from "upload-with-progress";
 
function FileUploader() {
  const { upload, progress, isUploading, error, abort } = useUpload();
 
  const handleFileChange = async (e: React.ChangeEvent<HTMLInputElement>) => {
    const file = e.target.files?.[0];
    if (!file) return;
 
    try {
      // The `upload` function returns the metadata from your backend
      const uploadedMeta = await upload(file, async () => {
        // Fetch the presigned URL from your API
        const response = await fetch("/api/get-presigned-url", {
          method: "POST",
          body: JSON.stringify({ name: file.name, type: file.type }),
        });
 
        // Expected response format: { presignedUrl: string, meta: any }
        return response.json();
      });
 
      console.log("Upload successful!", uploadedMeta);
    } catch (err) {
      console.error("Upload failed:", err);
    }
  };
 
  return (
    <div>
      <input type="file" onChange={handleFileChange} />
 
      {isUploading && (
        <div className="progress-bar">
          <p>Uploading... {progress}%</p>
          <progress value={progress} max="100" />
          <button onClick={abort}>Cancel</button>
        </div>
      )}
 
      {error && <p className="error">Error: {error}</p>}
    </div>
  );
}

Backend Requirements

The backend must return an object containing a presigned upload URL and metadata about the uploaded file.

{
  presignedUrl: string;
  meta: any; // The metadata you want to return
}

Example backend response:

{
  "presignedUrl": "https://bucket.s3.amazonaws.com/...",
  "meta": {
    "finalFileUrl": "https://cdn.example.com/video.mp4",
    "objectKey": "uploads/video.mp4"
  }
}

Progress Tracking

The hook exposes a progress state variable that is a number between 0 and 100 that represents the percentage of the file that has been uploaded.

const { progress } = useUpload();

This value updates in real-time as the file is being uploaded.

Cancelling an Upload

You can cancel an in-progress upload at any time.

const { abort } = useUpload();
 
abort();

This immediately stops the request and resets the upload state.