Installation

useApexxCloud Hook

A custom hook for granular control over the upload process.

Basic Usage

import { useApexxCloud } from "@apexxcloud/react";
import { useEffect, useRef } from "react";
import { useState } from "react";

export default function CustomUploader() {
  const { upload, uploadMultipart } = useApexxCloud();
  const [progress, setProgress] = useState(0);
  const abortController = useRef(new AbortController());

  const getSignedUrl = async (type: string, params: any) => {
    const response = await fetch(
      `http://localhost:5000/api/files/get-signed-url/${type}`,
      {
        method: "POST",
        body: JSON.stringify(params),
        headers: {
          "Content-Type": "application/json",
        },
      }
    );
    const data = await response.json();
    return data.url;
  };

  const handleUpload = async (file) => {
    setProgress(0);
    abortController.current = new AbortController();

    try {
      await upload(getSignedUrl, file, {
        signal: abortController.current.signal,
        onStart: (event) => {
          console.log(`Starting upload: ${event.file.name}`);
        },
        onProgress: (event) => {
          setProgress(event.progress);
        },
        onComplete: (event) => {
          console.log("Upload complete:", event.response);
          setProgress(0);
        },
        onError: (event) => {
          if (event.type === "abort") {
            console.log("Upload cancelled");
            setProgress(0);
          } else {
            console.error("Upload failed:", event.error);
          }
        },
      });
    } catch (error) {
      if (error instanceof DOMException && error.name === "AbortError") {
        console.log("Upload aborted");
      } else {
        console.error("Upload failed:", error);
      }
      setProgress(0);
    }
  };

  return (
    <div>
      <input
        type="file"
        onChange={(e) => {
          const file = e.target.files?.[0];
          if (file) handleUpload(file);
        }}
      />
      <button
        onClick={() => {
          abortController.current.abort();
          setProgress(0);
        }}
      >
        Cancel Upload
      </button>
      <progress value={progress} max="100" />
    </div>
  );
}

Multipart Upload Example

import { useApexxCloud } from "@apexxcloud/react";
import { useEffect, useRef } from "react";
import { useState } from "react";

export default function MultipartUploader() {
  const { upload, uploadMultipart } = useApexxCloud();
  const [progress, setProgress] = useState(0);
  const abortController = useRef(new AbortController());

  const getSignedUrl = async (type: string, params: any) => {
    const response = await fetch(
      `http://localhost:5000/api/files/get-signed-url/${type}`,
      {
        method: "POST",
        body: JSON.stringify(params),
        headers: {
          "Content-Type": "application/json",
        },
      }
    );
    const data = await response.json();
    return data.url;
  };

  const handleUpload = async (file) => {
    setProgress(0);
    abortController.current = new AbortController();

    try {
      //  just replace upload with uploadMultipart
      await uploadMultipart(getSignedUrl, file, {
        signal: abortController.current.signal,
        onStart: (event) => {
          console.log(`Starting upload: ${event.file.name}`);
        },
        onProgress: (event) => {
          setProgress(event.progress);
        },
        onComplete: (event) => {
          console.log("Upload complete:", event.response);
          setProgress(0);
        },
        onError: (event) => {
          if (event.type === "abort") {
            console.log("Upload cancelled");
            setProgress(0);
          } else {
            console.error("Upload failed:", event.error);
          }
        },
      });
    } catch (error) {
      if (error instanceof DOMException && error.name === "AbortError") {
        console.log("Upload aborted");
      } else {
        console.error("Upload failed:", error);
      }
      setProgress(0);
    }
  };

  return (
    <div>
      <input
        type="file"
        onChange={(e) => {
          const file = e.target.files?.[0];
          if (file) handleUpload(file);
        }}
      />
      <button
        onClick={() => {
          abortController.current.abort();
          setProgress(0);
        }}
      >
        Cancel Upload
      </button>
      <progress value={progress} max="100" />
    </div>
  );
}

Hook Return Value

PropertyTypeDescription
upload(getSignedUrl: GetSignedUrlFn, file: File, options?: UploadOptions) => Promise<any>Function for single file upload
uploadMultipart(getSignedUrl: GetSignedUrlFn, file: File, options?: MultipartUploadOptions) => Promise<any>Function for multipart upload
transformImageTransformBuilderBuilder for image transformations
transformVideoVideoTransformBuilderBuilder for video transformations
transformDocumentDocumentTransformBuilderBuilder for document transformations
transformWithString(path: string, transformations: string | string[]) => stringDirect transformation using strings

Upload Options

OptionTypeDescription
signalAbortSignalAbortSignal for cancelling upload
onStart(event: StartEvent) => voidCalled when upload starts
onProgress(event: ProgressEvent) => voidCalled during upload progress
onComplete(event: CompleteEvent) => voidCalled when upload completes
onError(event: ErrorEvent) => voidCalled if upload fails

Multipart Upload Options

Includes all Upload Options plus:

OptionTypeDescription
partSizenumberSize of each part in bytes (default: 5MB)
concurrencynumberNumber of concurrent part uploads (default: 3)
onPartComplete(part: PartCompleteEvent) => voidCalled when a part completes

Backend Implementation

See the JavaScript SDK documentation for details on implementing the backend signed URL endpoint.

File Uploader Component

The SDK provides a pre-built FileUploader component that you can use out of the box:

import { FileUploader } from "@apexxcloud/react";

function App() {
  const getSignedUrl = async (type, params) => {
    // Your signed URL implementation
  };

  return (
    <FileUploader
      getSignedUrl={getSignedUrl}
      onUploadComplete={(response) => console.log("Upload complete:", response)}
      onUploadError={(error) => console.error("Upload failed:", error)}
      multipart={false}
      accept={{ "image/*": [".png", ".jpg", ".jpeg"] }}
      maxSize={10} // MB
    />
  );
}

Component Props

PropTypeDescription
getSignedUrlGetSignedUrlFnFunction to get signed URLs from your backend
onUploadComplete(response: any) => voidCalled when upload completes successfully
onUploadError(error: Error) => voidCalled when upload fails
multipartbooleanEnable multipart upload for large files
acceptRecord<string, string[]>Accepted file types
maxSizenumberMaximum file size in MB

Custom Implementation

If you want to customize the uploader or build your own, here’s the complete implementation of our FileUploader component that you can use as a reference:

This implementation includes:

  • Drag and drop support
  • Upload progress tracking
  • Error handling
  • File type and size validation
  • Upload cancellation
  • Responsive design
  • Accessibility features

Requirements

  • React 16.8+ (Hooks support)
  • @apexxcloud/sdk-js as a peer dependency

Transformations

Image Transformations

import { useApexxCloud } from "@apexxcloud/react";

function ImageTransformExample() {
  const { transformImage } = useApexxCloud();

  // Basic transformations
  const url = transformImage
    .width(800)
    .height(600)
    .crop("fill")
    .quality("auto:good")
    .buildUrl("path/to/image.jpg");

  // Chaining multiple transformations
  const complexUrl = transformImage
    .width(800)
    .height(600)
    .crop("fill")
    .chain()
    .blur(20)
    .grayscale()
    .buildUrl("path/to/image.jpg");

  return (
    <div>
      <img src={url} alt="Transformed image" />
      <img src={complexUrl} alt="Complex transformed image" />
    </div>
  );
}

Video Transformations

function VideoTransformExample() {
  const { transformVideo } = useApexxCloud();

  // Basic video transformation
  const videoUrl = transformVideo
    .width(1280)
    .height(720)
    .format("mp4")
    .buildUrl("path/to/video.mp4");

  // Generate video thumbnail
  const thumbnailUrl = transformVideo
    .thumbnail(5.0) // Seek to 5 seconds
    .width(400)
    .height(300)
    .crop("fill")
    .buildUrl("path/to/video.mp4");

  return (
    <div>
      <video src={videoUrl} controls />
      <img src={thumbnailUrl} alt="Video thumbnail" />
    </div>
  );
}

Document Transformations

function DocumentTransformExample() {
  const { transformDocument } = useApexxCloud();

  // Convert document format
  const pdfUrl = transformDocument
    .format("pdf")
    .quality("auto:high")
    .buildUrl("path/to/document.docx");

  // Generate document thumbnail
  const thumbnailUrl = transformDocument
    .thumbnail(1) // First page
    .width(800)
    .height(1200)
    .buildUrl("path/to/document.pdf");

  return (
    <div>
      <iframe src={pdfUrl} />
      <img src={thumbnailUrl} alt="Document thumbnail" />
    </div>
  );
}

For detailed information about available transformation options, see the JavaScript SDK documentation.