Welcome to our React file upload tutorial. In this article, weโll cover how to enable file uploads in your React app from scratch. If you want a simple plug & play solution, try our React Filepicker Component (youโll need to create a free Filestack account to get your API key).
Understanding the File Upload Process in React:
Uploading files in a React app, such as images, documents, or any other file types, typically follows a structured approach:
- User File Selection: The journey begins with allowing the user to select a file. In React, this is commonly achieved by utilizing the
<input>
element with itstype
attribute set to โfileโ. This offers a user-friendly interface for file selection. When a file is chosen, itโs important to have an event handler in place. This event handler listens to any changes or interactions with the file input and updates the applicationโs state with the selected fileโs information. - Server Communication: Once the file information is captured and stored in the applicationโs state, the next pivotal step is sending it over to a server. This could be for processing, storage, or any other backend operation. Tools like
axios
or the nativefetch
API are frequently employed to handle this communication. They aid in making asynchronous HTTP requests to servers. Itโs crucial to wrap the selected file in aFormData
object, ensuring the data is properly formatted for transmission. - Feedback & Response Handling: Upon initiating communication with the server, always anticipate two outcomes: success or failure. Implementing feedback mechanisms like success messages, error alerts, or even displaying the uploaded file helps improve user experience. It provides assurance that their action (file upload) was successful or gives clarity if something went amiss.
- Error Handling: The digital realm isnโt always predictable. Issues might arise during the upload process, be it network glitches, file format mismatches, or server-side errors. Being prepared with a robust error-handling mechanism not only aids in troubleshooting but also ensures users arenโt left in the dark. Informative error messages and alternative solutions can steer users in the right direction.
- External Libraries and Tools: While React provides a solid foundation, sometimes external libraries or tools can expedite the development process. Tools like
axios
simplify HTTP communications. Moreover, services like Filestack offer out-of-the-box file uploading solutions, saving development time.
By adhering to this structured approach, developers can ensure a smooth and efficient file upload process in their React applications, enhancing both functionality and user satisfaction.
Now letโs dive in to the nitty gritty details.
Weโre starting with a freshly created react app with the default content removed.
import './App.css';
function App() {
return (
<div className="App">
</div>
);
}
export default App;
The first thing weโll do is create a simple form where our user can choose what file to upload.
import './App.css';
function App() {
return (
<div className="App">
<form>
<h1>React File Upload</h1>
<input type="file" />
<button type="submit">Upload</button>
</form>
</div>
);
}
export default App;
Next, weโll create a state variable, add an onChange event handler to the input element, and create a handleChange function to keep track of what file our user chose to upload.
import './App.css';
import React, {useState} from react;
function App() {
const [file, setFile] = useState()
function handleChange(event) {
setFile(event.target.files[0])
}
return (
<div className="App">
<form>
<h1>React File Upload</h1>
<input type="file" onChange={handleChange}/>
<button type="submit">Upload</button>
</form>
</div>
);
}
export default App;
Now that we know what file our user chose to upload, weโll add axios for making http requests, an onSubmit event handler to the form, and a handleSubmit function to upload the file using a http POST request.
import './App.css';
import React, {useState} from 'react';
import axios from 'axios';
function App() {
const [file, setFile] = useState()
function handleChange(event) {
setFile(event.target.files[0])
}
function handleSubmit(event) {
event.preventDefault()
const url = 'http://localhost:3000/uploadFile';
const formData = new FormData();
formData.append('file', file);
formData.append('fileName', file.name);
const config = {
headers: {
'content-type': 'multipart/form-data',
},
};
axios.post(url, formData, config).then((response) => {
console.log(response.data);
});
}
return (
<div className="App">
<form onSubmit={handleSubmit}>
<h1>React File Upload</h1>
<input type="file" onChange={handleChange}/>
<button type="submit">Upload</button>
</form>
</div>
);
}
export default App;
This is the critical step when enabling file uploads using React. Weโve created a config object to specify a โcontent-typeโ header for our http request. In order to upload files, the โcontent-typeโ header must be set to โmultipart/form-dataโ.
new FormData() creates a new empty formData object that we send as the payload in our POST request. Our POST request assumes there is an API endpoint on our backend server at http://localhost:3000/uploadFile.
Uploading Multiple Files
In many real-world applications, thereโs a need for users to upload more than one file at a time. Letโs enhance our React app to support multiple file uploads.
import './App.css'; import React, { useState } from 'react'; import axios from 'axios'; function App() { const [files, setFiles] = useState([]); const [uploadedFiles, setUploadedFiles] = useState([]); function handleMultipleChange(event) { setFiles([...event.target.files]); } function handleMultipleSubmit(event) { event.preventDefault(); const url = 'http://localhost:3000/uploadFiles'; const formData = new FormData(); files.forEach((file, index) => { formData.append(`file${index}`, file); }); const config = { headers: { 'content-type': 'multipart/form-data', }, }; axios.post(url, formData, config) .then((response) => { console.log(response.data); setUploadedFiles(response.data.files); }) .catch((error) => { console.error("Error uploading files: ", error); }); } return ( <div className="App"> <form onSubmit={handleMultipleSubmit}> <h1>React Multiple File Upload</h1> <input type="file" multiple onChange={handleMultipleChange} /> <button type="submit">Upload</button> </form> {uploadedFiles.map((file, index) => ( <img key={index} src={file} alt={`Uploaded content ${index}`} /> ))} </div> ); } export default App;
In this snippet, theinput
tag now has themultiple
attribute, allowing users to select multiple files. We're iterating over the selected files, adding each one to ourFormData
object, and then displaying each uploaded file in the app.
File Upload Progress
Another enhancement is to provide users with feedback on the progress of their file upload.
import './App.css';
import React, { useState } from 'react';
import axios from 'axios';
function App() {
const [file, setFile] = useState();
const [uploadProgress, setUploadProgress] = useState(0);
function handleChange(event) {
setFile(event.target.files[0]);
}
function handleSubmit(event) {
event.preventDefault();
const url = 'http://localhost:3000/uploadFile';
const formData = new FormData();
formData.append('file', file);
const config = {
headers: {
'content-type': 'multipart/form-data',
},
onUploadProgress: function(progressEvent) {
const percentCompleted = Math.round((progressEvent.loaded * 100) / progressEvent.total);
setUploadProgress(percentCompleted);
}
};
axios.post(url, formData, config)
.then((response) => {
console.log(response.data);
})
.catch((error) => {
console.error("Error uploading file: ", error);
});
}
return (
<div className="App">
<form onSubmit={handleSubmit}>
<h1>React File Upload with Progress</h1>
<input type="file" onChange={handleChange} />
<button type="submit">Upload</button>
<progress value={uploadProgress} max="100"></progress>
</form>
</div>
);
}
export default App;
Here, weโve added an onUploadProgress
function to our Axios config. This function updates our uploadProgress
state variable with the current percentage of the upload. We display this percentage using the HTML5 progress
element.
These enhancements not only provide a better user experience but also cater to more practical use cases in file uploading scenarios. Now letโs move forward to displaying the uploaded file.
Displaying the Uploaded File in the React App
After successfully uploading a file, itโs often beneficial for the user to get feedback and see the file they just uploaded. In this section, weโll update the state with the uploaded fileโs URL and display the file in our React app.
import './App.css';
import React, {useState} from 'react';
import axios from 'axios';
function App() {
const [file, setFile] = useState()
const [uploadedFileURL, setUploadedFileURL] = useState(null)
function handleChange(event) {
setFile(event.target.files[0])
}
function handleSubmit(event) {
event.preventDefault()
const url = 'http://localhost:3000/uploadFile';
const formData = new FormData();
formData.append('file', file);
formData.append('fileName', file.name);
const config = {
headers: {
'content-type': 'multipart/form-data',
},
};
axios.post(url, formData, config).then((response) => {
setUploadedFileURL(response.data.fileUrl);
});
}
return (
<div className="App">
<form onSubmit={handleSubmit}>
<h1>React File Upload</h1>
<input type="file" onChange={handleChange}/>
<button type="submit">Upload</button>
</form>
{uploadedFileURL && <img src={uploadedFileURL} alt="Uploaded content"/>}
</div>
);
}
export default App;
In this snippet, we added a new state variable uploadedFileURL which holds the URL of the uploaded file. After we get a successful response from the server, we update this state variable with the fileโs URL which we then use to display the image in our application.
Handling React File Upload Errors
Itโs good practice to handle potential errors that might occur during the file upload process. Letโs add some error handling to our handleSubmit function:
import './App.css';
import React, {useState} from 'react';
import axios from 'axios';
function App() {
const [file, setFile] = useState();
const [uploadedFile, setUploadedFile] = useState();
const [error, setError] = useState();
function handleChange(event) {
setFile(event.target.files[0]);
}
function handleSubmit(event) {
event.preventDefault();
const url = 'http://localhost:3000/uploadFile';
const formData = new FormData();
formData.append('file', file);
formData.append('fileName', file.name);
const config = {
headers: {
'content-type': 'multipart/form-data',
},
};
axios.post(url, formData, config)
.then((response) => {
console.log(response.data);
setUploadedFile(response.data.file);
})
.catch((error) => {
console.error("Error uploading file: ", error);
setError(error);
});
}
return (
<div className="App">
<form onSubmit={handleSubmit}>
<h1>React File Upload</h1>
<input type="file" onChange={handleChange}/>
<button type="submit">Upload</button>
</form>
{uploadedFile && <img src={uploadedFile} alt="Uploaded content"/>}
{error && <p>Error uploading file: {error.message}</p>}
</div>
);
}
export default App;
In the above code, weโve added a catch block to our axios POST request that sets an error state variable in case of an error. We also render an error message to the screen if there was an error uploading the file.
By extending our application with these two sections, weโve made it more user-friendly and robust. Itโs now not only possible for users to upload files, but also to view the uploaded files and receive error messages in case something goes wrong during the upload process.
Weโre done! If you want to learn about how to setup the backend server that would receive the POST request we made in this article, check out our articles on how to upload a file using NodeJS (or with Python if you prefer).
If you donโt want to go through the trouble of setting up a server, consider signing up for a free Filestack account.
FAQs
What is the purpose of the โhandleChangeโ function in the file upload process?
The โhandleChangeโ function is used to update the state with the file that a user chooses to upload. It sets the โfileโ state variable to the file object from the event triggered by the file input.
Why do we use โmultipart/form-dataโ as the content-type in the config object?
When you want to upload a file, the โcontent-typeโ should be set to โmultipart/form-dataโ. This type is necessary when you are sending binary data in the body of the request, like the contents of a file.
How does the React app display the uploaded file?
Once the file is uploaded, the server returns the URL of the uploaded file which is then stored in the โuploadedFileโ state variable. This URL is used as the โsrcโ attribute of an img tag, allowing the uploaded image to be displayed in the React app.
How does the app handle errors that might occur during the file upload process?
The app handles errors by using a .catch() block with the axios POST request. If an error occurs during the file upload process, the catch block is executed, setting the โerrorโ state variable with the error message. This error message is then displayed on the screen.
What if I donโt want to set up a server for file upload functionality?
If you donโt want to set up a server, you could use services like Filestack. We provide SDKs & APIs for file uploading functionality that you can integrate into your app with just a few lines of code.
A Product Marketing Manager at Filestack with four years of dedicated experience. As a true technology enthusiast, they pair marketing expertise with a deep technical background. This allows them to effectively translate complex product capabilities into clear value for a developer-focused audience.
Read More โ