Uploading a single file
To upload a single file in React, you need to set the content-type
and content-length
headers and provide the file contents as the request body:
import { ChangeEvent, useState } from 'react';
function FileUploadSingle() {
const [file, setFile] = useState<File>();
const handleFileChange = (e: ChangeEvent<HTMLInputElement>) => {
if (e.target.files) {
setFile(e.target.files[0]);
}
};
const handleUploadClick = () => {
if (!file) {
return;
}
// 👇 Uploading the file using the fetch API to the server
fetch('https://httpbin.org/post', {
method: 'POST',
body: file,
// 👇 Set headers manually for single file upload
headers: {
'content-type': file.type,
'content-length': `${file.size}`, // 👈 Headers need to be a string
},
})
.then((res) => res.json())
.then((data) => console.log(data))
.catch((err) => console.error(err));
};
return (
<div>
<input type="file" onChange={handleFileChange} />
<div>{file && `${file.name} - ${file.type}`}</div>
<button onClick={handleUploadClick}>Upload</button>
</div>
);
}
export default FileUploadSingle;
- First, we add an
input
element withtype="file"
attribute. - We can store the selected file in React component state, after receiving it from the
onChange
event. Since we're only able to select a single file, we can get it from thefiles
array on the input:e.target.files[0]
. - We can upload the file using the Fetch API. We need to set the set
body
to the file we received from the input and the headers:content-type
to the filetype
and thecontent-length
tofile.size
. Note that headers must be string values.
I used a httpbin.org API that accepts file uploads and responds with a copy of the request you send. Here's the result:
Uploading files usually requires some work on the backend to accept, store, and serve those files upon request. If you'd like to learn that and more, I highly recommend educative.io courses.
Here's one that will help you master full-stack development with React:
Uploading multiple files
To upload multiple files from input
element in React, you need to use the FormData JavaScript API and encode the request as multipart/form-data
.
The first difference from our single file upload example is the addition of multiple
attribute on the input
element.
Instead of storing a single file in the React component state, we save the whole FileList
in state
FileList
is not an array, so we can't use regular array methods like map
or forEach
. However, we can still access the members by index fileList[0]
, loop through the files using for..of
or spread them. To upload multiple files:
- Create a
FormData
object:const data = new FormData()
; - Append each file you want to upload using FormData.append() - it accepts a form field name, the file, and a file name as parameters.
- Using the Fetch API, upload the files by setting form data as
body
. Note that when you use form data you don't need to set headers manually. It's taken care of by fetch API.
Here's what it looks like:
Customizing the file input
The default input
element doesn't offer much in terms of styling it. To create a custom file upload input in React, you will need to hide the native file upload input and trigger the click
events on the input using refs:
Only the input
element with file type can open the files for selection in the browser. To upload a file when clicking the custom button, we need to trigger the click()
event on the input: inputRef.current?.click();
If we don't want to show the native input, we can hide it by adding the display: none
CSS property in it's style
attribute or by applying a CSS class that sets the display property to none
(e.g. in Tailwind, the class name is hidden
).
From then on, you can save the selected files in state or upload them immediately. You now have full customization of the file upload input:
Conclusion
In React file upload is implemented by using the HTML input
element and some JavaScript to make a POST/PUT request to the server with the FormData that contains the selected files.
Your server will then need to process multipart form data to accept file uploads. You can use Multer in Node.js to implement that or upload the files directly to Amazon S3 if that's what you want.
You can find the code used in the examples in my GitHub repo.
Now that you know how to handle files on the front end you should also learn to handle them on the backend, I recommend this full-stack course on educative.io to help you do that: