How to Create a Simple Form Submit with Files
Feb 5, 2020 • 13 Minute Read
Introduction
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.
Simple File Upload Using Form
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.
- Form element
- Input control with type as a file
- Submit button to submit the form
- File change event to get updated file details
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.
render() {
return (
<div>
<h2>File upload using form in React</h2>
<hr />
<div>
<form>
<table>
<tr>
<td>Select File :</td>
</tr>
<tr>
<input type="file" />
</tr>
</table>
</form>
</div>
</div>
);
}
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.
<form>
<table>
<tr>
<td>Select File :</td>
</tr>
<tr>
<input onChange={this.onFileChange} type="file" />
</tr>
</table>
</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.
onFileChange(e) {
const file = e.target.files[0];
console.log(file.name);
console.log(file.size);
console.log(file.type);
}
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.
import React, { Component } from "react";
class Simplefileupload extends Component {
constructor() {
super();
this.onFileChange = this.onFileChange.bind(this);
}
onFileChange(e) {
const file = e.target.files[0];
console.log(file.name);
console.log(file.size);
console.log(file.type);
}
render() {
return (
<div>
<h2>File upload using form in React</h2>
<hr />
<div>
<form>
<table>
<tr>
<td>Select File :</td>
</tr>
<tr>
<input onChange={this.onFileChange} type="file" />
</tr>
</table>
</form>
</div>
</div>
);
}
}
export 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.
Upload Multiple Files Using Simple Form
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.
<form>
<table>
<tr>
<td>Select File :</td>
</tr>
<tr>
<input onChange={this.onFileChange} type="file" multiple />
</tr>
</table>
</form>
And in order to access the multiple files, we need to modify the change event as well, which looks like this.
// for multiple file
onFileChange(e) {
const file = e.target.files;
console.log(file);
}
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.
File Upload Using Redux-form
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.
npm install redux
npm install react-redux
npm install redux-form
npm 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.
import { createStore, combineReducers } from "redux";
import { reducer as reduxFormReducer } from "redux-form";
const reducer = combineReducers({
form: reduxFormReducer
});
const store = createStore(reducer);
export 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.
import React, { Component } from "react";
import { Field, reduxForm } from "redux-form";
class Fileuploadtoserver extends Component {
constructor() {
super();
this.state = {
name: "React"
};
}
renderInput = ({ input, type, meta }) => {
const { mime } = this.props;
return (
<div>
<input
name={input.name}
type={type}
accept={mime}
onChange={event => this.handleChange(event, input)}
/>
</div>
);
};
handleChange = (event, input) => {
event.preventDefault();
let imageFile = event.target.files[0];
if (imageFile) {
const localImageUrl = URL.createObjectURL(imageFile);
const imageObject = new window.Image();
imageObject.onload = () => {
imageFile.width = imageObject.naturalWidth;
imageFile.height = imageObject.naturalHeight;
input.onChange(imageFile);
URL.revokeObjectURL(imageFile);
};
imageObject.src = localImageUrl;
}
};
render() {
const { handleSubmit } = this.props;
return (
<div>
<h2>File upload to server using redux-form in React</h2>
<hr />
<div>
<form onSubmit={handleSubmit(this.onFormSubmit)}>
<table>
<tr>
<td>Select File :</td>
</tr>
<tr>
<td>
<Field
name="image"
type="file"
component={this.renderInput}
/>
</td>
</tr>
<tr>
<td>
<button type="submit">Submit</button>
</td>
</tr>
</table>
</form>
</div>
</div>
);
}
}
export default reduxForm({
form: "myfileupload"
})(Fileuploadtoserver);
Let’s look at what we have implemented so far in this component.
- A form with the redux-form’s submit an event
- The <Filed> element, which is the part of redux-form that renders the input type as a file using the generic function renderInput()
- One input file change event that gets the file details and, based on the details, creates the new image object along with different keys like width and height
- The 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.
onFormSubmit = data => {
let formData = new FormData();
formData.append("name", data.image.name);
formData.append("image", data.image);
const config = {
headers: { "content-type": "multipart/form-data" }
};
const url = "API_URL";
post(url, formData, config)
.then(function(response) {
console.log("FILE UPLOADED SUCCESSFULLY");
})
.catch(function(error) {
console.log("ERROR WHILE UPLOADING FILE");
});
};
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.
Validating Files Before Upload
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.
validateSize = imageFile => {
if (imageFile && imageFile.size) {
const imageFileKb = imageFile.size / 1024;
if (imageFileKb < 100) {
return `Image should be > 100 kb`;
}
}
};
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.
<form onSubmit={handleSubmit(this.onFormSubmit)}>
<table>
<tr>
<td>Select File :</td>
</tr>
<tr>
<td>
<Field
name="image"
type="file"
validate={[this.validateSize]}
component={this.renderInput}
/>
</td>
</tr>
<tr>
<td>
<button type="submit">Submit</button>
</td>
</tr>
</table>
</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.
Validate the Number of Files
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.
maxSelectFile = event => {
if (event && event.target.files) {
let files = event.target.files;
if (files.length > 2) {
const errorMsg = "More than 2 files are not allowed";
event.target.value = null;
console.log(errorMsg);
return false;
}
return true;
}
};
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.
Conclusion
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.