Skip to main content
react-mediadrop/xhr-upload covers a generic REST-ish endpoint. For anything else — a provider SDK, a test double, a more advanced protocol — write your own transport against the same contract:

What must a transport do?

  • One file, one attempt. Send the file, report progress, resolve or reject. The queue decides whether to retry — you don’t.
  • Call onProgress as the upload progresses. Use total: null when the length can’t be determined.
  • Wire signal’s abort event to whatever cancellation your transport has (e.g. XMLHttpRequest.abort(), fetch’s own signal support).
  • Resolve with { response } — anything, opaque to the engine (e.g. the server’s parsed JSON body) — on success. Reject on failure.
  • Do not implement your own retry or backoff inside the transport. Use the shared withRetry engine (re-exported from react-mediadrop) for any finer-grained retry the transport itself needs — see Upload. This is a direct reaction to a real anti-pattern: libraries that let every transport carry its own independent copy of retry/backoff logic end up with subtly different retry behavior per transport, and no single place to fix a bug in it. react-mediadrop has one retry engine, and this is where you plug into it.
  • Do not implement your own concurrency limit. The queue decides how many uploads run at once; your transport just services one call at a time when asked.

What does a minimal transport look like?

This example reports progress only once, at completion, because fetch has no cross-browser upload-progress API — this is exactly why react-mediadrop/xhr-upload uses XMLHttpRequest instead. If your task needs real incremental progress, use XMLHttpRequest.upload.onprogress the way the reference transport does — see its API reference.

What about multi-request transports?

A multi-request transport (splitting one file into several requests, like a resumable protocol) is still “one file, one upload() call” from the queue’s point of view — internally it may issue many requests and retry individual ones via the shared withRetry, called again for that finer-grained retry, but never a second, hand-rolled retry implementation. Resumable transports (S3 multipart, tus) aren’t part of this codebase today — see Roadmap.

Upload

The queue, concurrency, retry, and cancel

Core concepts

The file model, the store, and drag state