Better Upload

TanStack Query

If you prefer to use TanStack Query instead of the hooks provided by Better Upload, you can do so by using the uploadFile and uploadFiles functions with the useMutation hook from TanStack Query.

Example

The complete code for a simple uploader is below.

'use client';

import { uploadFiles } from '@better-upload/client';
import { useMutation } from '@tanstack/react-query';

export function Uploader() {
  const { mutate: upload, isPending } = useMutation({
    mutationFn: async (files: File[]) => {
      return uploadFiles({
        files,
        route: 'form',
        onFileStateChange: ({ file }) => {
          // you handle the progress of each file
          console.log(file);
        },
      });
    },
    onSuccess: ({ files, failedFiles, metadata }) => {
      console.log({
        files,
        failedFiles,
        metadata,
      });
    },
    onError: (error) => {
      console.error(error);
    },
  });

  return (
    <input
      type="file"
      multiple
      disabled={isPending}
      onChange={(e) => {
        if (e.target.files) {
          upload(Array.from(e.target.files));
        }
      }}
    />
  );
}

Tracking upload state

Note that by directly using the upload functions, you need to track the state of each file upload yourself. This is simple to do, an example for multiple files is below.

'use client';

import {
  type FileUploadInfo,
  type UploadStatus,
  uploadFiles,
} from '@better-upload/client';
import { useMutation } from '@tanstack/react-query';
import { useState } from 'react';

export function Uploader() {
  const [uploadState, setUploadState] = useState(
    () => new Map<string, FileUploadInfo<UploadStatus>>()
  );

  const { mutate: upload, isPending } = useMutation({
    mutationFn: async (files: File[]) => {
      return uploadFiles({
        files,
        route: 'form',
        onFileStateChange: ({ file }) => {
          setUploadState((prev) =>
            new Map(prev).set(file.objectInfo.key, file)
          );
        },
      });
    },
  });

  return (
    <input
      type="file"
      multiple
      disabled={isPending}
      onChange={(e) => {
        if (e.target.files) {
          upload(Array.from(e.target.files));
        }
      }}
    />
  );
}

On this page

Sponsored by
Next.js Weekly

Stay up to date on Next.js

A weekly newsletter to keep up with what's happening in the ecosystem.

Need software licensing?

Simple licensing for software, easily distribute your product.

  • - payment automation
  • - customer portal
  • - offline licensing