React is a JavaScript-based library used to create remarkable UI components using component-based architecture. All functionality can be divided into generic components reusable any time during the web development.
In web development, file upload functionality is a common feature that most appls already have, so the file upload process can be a little different from app to app.
File upload is customarily used to upload files, for example, images, documents (doc, pdf, xls, and so on), audio, video, and many other file types.
In this guide, we will learn how to create file upload functionality through a form in React.
We can quickly create a simple form with a submit button to allow file upload. We just need to manage the event for the change of the selected file.
The primary requirements for the file upload include the below element and configuration.
This is the standard way to configure file upload directly. We can also have different ways of implementation based on different requirements.
Let’s start with a simple approach.Below is a code snippet for the form.
1render() {
2 return (
3 <div>
4 <h2>File upload using form in React</h2>
5 <hr />
6 <div>
7 <form>
8 <table>
9 <tr>
10 <td>Select File :</td>
11 </tr>
12 <tr>
13 <input type="file" />
14 </tr>
15 </table>
16 </form>
17 </div>
18 </div>
19 );
20 }
Here in this snippet, we have the form
element, and inside the form element, the input
element is a type of file that allows us to select the file from the file dialog that appears when we click on the file upload control.
But this form doesn't work because we don’t have an event implemented as soon as we click a file, so we won’t get the file details submitted to the server. We should have one change event to address that.
1<form>
2 <table>
3 <tr>
4 <td>Select File :</td>
5 </tr>
6 <tr>
7 <input onChange={this.onFileChange} type="file" />
8 </tr>
9 </table>
10</form>
Along with the file input, we have an event called onFileChange()
, which is used to get the latest selected file by the end-user. In the end, we will get all the details of the selected file.
Let’s implement the change event as soon as the file has changed, like this.
1onFileChange(e) {
2 const file = e.target.files[0];
3 console.log(file.name);
4 console.log(file.size);
5 console.log(file.type);
6 }
In this event, we get the event object, and by using e.target.file[0]
, the file can be accessible along with the different properties of the selected file, such as the name of the file, its size, and the type of file.
Here it is the complete code snippet for the simple file upload along with the form.
1import React, { Component } from "react";
2
3class Simplefileupload extends Component {
4 constructor() {
5 super();
6 this.onFileChange = this.onFileChange.bind(this);
7 }
8
9 onFileChange(e) {
10 const file = e.target.files[0];
11 console.log(file.name);
12 console.log(file.size);
13 console.log(file.type);
14 }
15
16 render() {
17 return (
18 <div>
19 <h2>File upload using form in React</h2>
20 <hr />
21 <div>
22 <form>
23 <table>
24 <tr>
25 <td>Select File :</td>
26 </tr>
27 <tr>
28 <input onChange={this.onFileChange} type="file" />
29 </tr>
30 </table>
31 </form>
32 </div>
33 </div>
34 );
35 }
36}
37
38export default Simplefileupload;
Keep in mind that we don’t have any button inside the form, but we can also use the submit button inside the form to implement the HTTP call, which sends the file to the server.
In the above example, there is one input with the type as a file, but using that file upload we will not be able to select multiple files at a time. The solutions is to add one additional property called multiple
that allows us to select multiple files.
We need to update the input control like this.
1<form>
2 <table>
3 <tr>
4 <td>Select File :</td>
5 </tr>
6 <tr>
7 <input onChange={this.onFileChange} type="file" multiple />
8 </tr>
9 </table>
10</form>
And in order to access the multiple files, we need to modify the change event as well, which looks like this.
1// for multiple file
2 onFileChange(e) {
3 const file = e.target.files;
4 console.log(file);
5 }
If you open the browser console, you will see the array of the file by selecting multiple files from the file dialog. This is how we can allow the user to select multiple files at a time.
We have seen the simple approach to upload the file using <form>
, but if you have to use redux-form
along with the form in React, the standard form won’t be suitable.
In that case, you'll need to set up redux into the React application for redux-form
to work.
Installation
Before getting started with the example, we should install a few dependencies, given below.
1npm install redux
2npm install react-redux
3npm install redux-form
4npm install axios
Tthe next step is to configure redux in our React app and create a new file called store.js
. The code snippet should look like this.
1import { createStore, combineReducers } from "redux";
2import { reducer as reduxFormReducer } from "redux-form";
3
4const reducer = combineReducers({
5 form: reduxFormReducer
6});
7const store = createStore(reducer);
8
9export default store;
We have created the store using the method createStore()
. long with the method, an additional argument, the reducer
, is used to contain the instance of the redux form.
Now our store object is created and we will be able to use redux-form
in our application.
Our next step is to create the form by using the redux-form configuration into the component. The basic structure looks like this.
1import React, { Component } from "react";
2import { Field, reduxForm } from "redux-form";
3
4class Fileuploadtoserver extends Component {
5 constructor() {
6 super();
7 this.state = {
8 name: "React"
9 };
10 }
11
12 renderInput = ({ input, type, meta }) => {
13 const { mime } = this.props;
14 return (
15 <div>
16 <input
17 name={input.name}
18 type={type}
19 accept={mime}
20 onChange={event => this.handleChange(event, input)}
21 />
22 </div>
23 );
24 };
25
26 handleChange = (event, input) => {
27 event.preventDefault();
28 let imageFile = event.target.files[0];
29 if (imageFile) {
30 const localImageUrl = URL.createObjectURL(imageFile);
31 const imageObject = new window.Image();
32
33 imageObject.onload = () => {
34 imageFile.width = imageObject.naturalWidth;
35 imageFile.height = imageObject.naturalHeight;
36 input.onChange(imageFile);
37 URL.revokeObjectURL(imageFile);
38 };
39 imageObject.src = localImageUrl;
40 }
41 };
42
43 render() {
44 const { handleSubmit } = this.props;
45
46 return (
47 <div>
48 <h2>File upload to server using redux-form in React</h2>
49 <hr />
50 <div>
51 <form onSubmit={handleSubmit(this.onFormSubmit)}>
52 <table>
53 <tr>
54 <td>Select File :</td>
55 </tr>
56 <tr>
57 <td>
58 <Field
59 name="image"
60 type="file"
61 component={this.renderInput}
62 />
63 </td>
64 </tr>
65 <tr>
66 <td>
67 <button type="submit">Submit</button>
68 </td>
69 </tr>
70 </table>
71 </form>
72 </div>
73 </div>
74 );
75 }
76}
77
78export default reduxForm({
79 form: "myfileupload"
80})(Fileuploadtoserver);
Let’s look at what we have implemented so far in this component.
<Filed>
element, which is the part of redux-form that renders the input type as a file using the generic function renderInput()
reduxForm()
method, which is used to initialize the redux-form with an additional property called form
that is used to identify the name of the form.We have configured all required configurations except the form submit event, so as soon as we change the file, all details will be configured for the selected file.
The form submit event, called onFormSubmit()
, will look like this.
1onFormSubmit = data => {
2 let formData = new FormData();
3 formData.append("name", data.image.name);
4 formData.append("image", data.image);
5 const config = {
6 headers: { "content-type": "multipart/form-data" }
7 };
8 const url = "API_URL";
9 post(url, formData, config)
10 .then(function(response) {
11 console.log("FILE UPLOADED SUCCESSFULLY");
12 })
13 .catch(function(error) {
14 console.log("ERROR WHILE UPLOADING FILE");
15 });
16 };
This method contains the Axios POST
request, which is used to send the selected file to the server as the request data in the form of FormData()
.
Note : Before using the Axios package, we need to import that package like this.
import { post } from "axios";
Now, if you run this example by changing the API_URL
, we will be able to send the image data to the server without any problem.
When working with a file upload, we may want some restrictions in terms of validation. For example, we might restrict the file upload if specific conditions are not met.
Thus, we need to validate the file before it goes to the server. Let’s say we have to restrict the file based on size. We can implement a simple function like this.
1validateSize = imageFile => {
2 if (imageFile && imageFile.size) {
3 const imageFileKb = imageFile.size / 1024;
4
5 if (imageFileKb < 100) {
6 return `Image should be > 100 kb`;
7 }
8 }
9 };
The function validateSize()
gets the file detail, and based on the file size, we return a specific message that the file size should not be larger than the required size.
Now let’s modify our file upload control to apply the file size validation, like this.
1<form onSubmit={handleSubmit(this.onFormSubmit)}>
2 <table>
3 <tr>
4 <td>Select File :</td>
5 </tr>
6 <tr>
7 <td>
8 <Field
9 name="image"
10 type="file"
11 validate={[this.validateSize]}
12 component={this.renderInput}
13 />
14 </td>
15 </tr>
16 <tr>
17 <td>
18 <button type="submit">Submit</button>
19 </td>
20 </tr>
21 </table>
22</form>
As you can see, we have added an additional property called validate
that accepts the validator function as a value.
After the validation implementation, the file will always be validated against the size. If the file size is less than or equal to the defined size, then the file can be sent to the server; otherwise, it will not.
We can also implement other types of validation, including type of file, name of file, or height and width of the file.
We can also restrict the number of files sent to the server. For example, we may have the requirement that we should not allow more than two files to be sent to the server. In such cases, we would write logic something like this.
1maxSelectFile = event => {
2 if (event && event.target.files) {
3 let files = event.target.files;
4 if (files.length > 2) {
5 const errorMsg = "More than 2 files are not allowed";
6 event.target.value = null;
7 console.log(errorMsg);
8 return false;
9 }
10 return true;
11 }
12 };
Here in this function, maxSelectFile(),
we are validating the total number of files being selected, and if it exceeds two, the maximum file number error message will appear.
This is how we can implement different file validators based on functional requirements.
In this guide, we have learned how to implement file upload functionality using a simple form as well as the redux-form
approach.
I hope this guide was helpful for you. Stay tuned for more advanced guides.