0Pricing
React Academy · Lesson

Uploading Files to a Backend API

Use FormData and fetch to POST files and track upload progress.

Uploading Files to a Backend API is a free React Academy lesson on CoddyKit — lesson 4 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the React Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.

Welcome

In this lesson you will use the FormData API and fetch to POST files to a backend, track upload progress with XMLHttpRequest, and display upload state in React.

FormData API

FormData is a browser API that builds multipart/form-data request bodies — the format servers expect for file uploads. Append the file and any metadata fields to a FormData object.
const formData = new FormData();
formData.append('file', selectedFile);
formData.append('description', 'Profile photo');

Uploading with fetch

Pass the FormData object as the fetch body. Do NOT set Content-Type manually — the browser sets the correct multipart boundary automatically.
const response = await fetch('/api/upload', {
  method: 'POST',
  body: formData,
  // Do not set Content-Type header here!
});

Upload State Management

Track upload state with three state variables: `uploading` (boolean), `progress` (0–100), and `error` (string or null). Show spinners, progress bars, and error messages based on these.
const [uploading, setUploading] = useState(false);
const [progress, setProgress] = useState(0);
const [error, setError] = useState(null);

Upload Progress with XMLHttpRequest

The fetch API does not support upload progress events. Use XMLHttpRequest's `upload.onprogress` event to get percentage updates.
const xhr = new XMLHttpRequest();
xhr.upload.onprogress = (e) => {
  if (e.lengthComputable) {
    setProgress(Math.round((e.loaded / e.total) * 100));
  }
};
xhr.open('POST', '/api/upload');
xhr.send(formData);

Wrapping XHR in a Promise

Wrap the XMLHttpRequest call in a Promise so you can await it and use async/await error handling.
function uploadFile(file) {
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest();
    xhr.onload = () => resolve(xhr.response);
    xhr.onerror = () => reject(new Error('Upload failed'));
    xhr.upload.onprogress = (e) => setProgress(Math.round(e.loaded / e.total * 100));
    xhr.open('POST', '/api/upload');
    xhr.send(new FormData().set && (() => { const f = new FormData(); f.append('file', file); xhr.send(f); })());
  });
}

Handling the Server Response

Parse the server's JSON response after a successful upload. Update UI state with the returned URL or ID.
const res = await fetch('/api/upload', { method: 'POST', body: fd });
if (!res.ok) throw new Error('Upload failed');
const { url } = await res.json();
setUploadedUrl(url);

Error Handling

Always catch network and server errors. Display a user-friendly error message and allow retrying. Reset the progress and uploading state in the catch block.
try {
  setUploading(true);
  await uploadToServer(file);
} catch (err) {
  setError(err.message);
} finally {
  setUploading(false);
}

Cancelling an Upload

Use an AbortController with fetch to cancel an in-progress upload. Store the controller in a ref so you can call abort() from a cancel button.
const abortRef = useRef();

const start = async () => {
  abortRef.current = new AbortController();
  await fetch('/api/upload', { body: fd, signal: abortRef.current.signal });
};
const cancel = () => abortRef.current?.abort();

Multiple File Uploads

Upload multiple files in parallel using Promise.all, or sequentially with a for-of loop. Track individual progress per file with an object keyed by filename.

Quick Check

Why should you NOT manually set the Content-Type header when using fetch with FormData?

Recap

Use FormData to build upload payloads. Fetch without Content-Type for auto-boundary. Use XMLHttpRequest upload.onprogress for progress tracking. Handle errors gracefully and support cancellation with AbortController.

Course Complete

Congratulations! You finished **Uncontrolled Components & File Uploads**. You can now handle uncontrolled inputs, file selection, drag-and-drop, and multipart uploads with progress tracking.

Frequently asked questions

Is the “Uploading Files to a Backend API” lesson free?

Yes — the full text of “Uploading Files to a Backend API” is free to read here on the web, and the React Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the React Academy course, upgrade to CoddyKit PRO.

What will I learn in “Uploading Files to a Backend API”?

Use FormData and fetch to POST files and track upload progress. You practise React Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start React Academy?

No prior experience is required. React Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 4 of 4, so you can start here or from the beginning and move at your own pace.

How long does the “Uploading Files to a Backend API” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this React Academy lesson?

Yes. Every React Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. Uncontrolled Inputs with useRef
  2. File Input & Reading File Data
  3. Drag & Drop File Upload UI
  4. Uploading Files to a Backend API
← Back to React Academy