We can upload multiple files in React by using a mix of FormData() interface and the Fetch API.
For this example, we want to build React app that uploads a few files and shows a busy indicator the files are sent to the server. I've made this video with the completed example:
And here is the full code for it:
const API_URL = 'https://httpbin.org/post'
const API_METHOD = 'POST'
const STATUS_IDLE = 0
const STATUS_UPLOADING = 1
const App = () => {
const [files, setFiles] = React.useState([])
const [status, setStatus] = React.useState(STATUS_IDLE)
const uploadFiles = (data)=> {
setStatus(STATUS_UPLOADING);
fetch(API_URL, {
method: API_METHOD,
body: data,
})
.then((res) => res.json())
.then((data) => console.log(data))
.catch((err) => console.error(err))
.finally(() => setStatus(STATUS_IDLE))
}
const packFiles = (files)=> {
const data = new FormData();
[...files].forEach((file, i) => {
data.append(`file-${i}`, file, file.name)
})
return data
}
const handleUploadClick = () => {
if (files.length) {
const data = packFiles(files)
uploadFiles(data)
}
}
const renderFileList = () => (<ol>
{[...files].map((f, i) => (
<li key={i}>{f.name} - {f.type}</li>
))}
</ol>)
const renderButtonStatus = () => (
(status === STATUS_IDLE) ?
'Send to server' :
<img src = "./load.svg" />
)
return (<div>
<input
type="file"
accept="image/*"
multiple
onChange={(e)=> setFiles(e.target.files)} />
{renderFileList()}
<button onClick={handleUploadClick} disabled={status === STATUS_UPLOADING}>
{renderButtonStatus()}
</button>
</div>)
}
The whole magic of the example happens in packFiles()
, where we use the FormData.append()
method to wrap all the files into one single entity that is sent via a fetch request.
If you want to dive more into the FormData interface I've written two articles about it: a basic intro for fetch() and FormData and one that goes more into details about FormData and the append() method.
We are using the HttpBin service as a dummy endpoint placeholder. After receiving the request it just outputs back a JSON object where we can see the uploaded items in the files
property.
The file uploader was customized so that it allows the section of multiple files and it takes only images as inputs. You can use the multiple
and accept
attributes to change these behaviors.
The actual files state
variable is not an array, but it's iterable, so we can use the spread operator to get an array of files:
const renderFileList = () => (<ol>
{[...files].map((f, i) => (
<li key={i}>{f.name} - {f.type}</li>
))}
</ol>)
As a final note, you can use the URL.createObjectURL() to make image previews for the uploaded files.
You can see here the GitHub repo for this example, and here is the live working app.
📖 50 Javascript, React and NextJs Projects
Learn by doing with this FREE ebook! Not sure what to build? Dive in with 50 projects with project briefs and wireframes! Choose from 8 project categories and get started right away.
📖 50 Javascript, React and NextJs Projects
Learn by doing with this FREE ebook! Not sure what to build? Dive in with 50 projects with project briefs and wireframes! Choose from 8 project categories and get started right away.