Creating a File Upload Component with React

In this tutorial you will learn how to create a working file upload component with react from scratch using no dependencies other than react itself.

You will learn how to upload files and display the upload progress using react.

Here is what the result will look like:

Also, we will start by building a server we can upload files to using nodejs and express. We will walk through the full full-stack process to make sure you end up with a working system.

Ready?

Let's get started!

Creating the express server to upload to

Before we can have a react app upload anything, we need to have a server we can upload to, right?

In this tutorial, we are going to implement a file upload server using node.js and express, that allows file to be uploaded in in the multipart format.

Setting up a new project

To set up a new project, create a new project directory containing two folders app and server.

Next, open the command line pointing at the server directory and initialize a new npm-project using the

npm init

command. It will ask you for some information. You can pass it in or just hit enter.

For the server, we will also need two JavaScript files. Create the following files in the project directory:

server.jsupload.js

Go ahead and create them inside of the server directory.

External Dependencies

Our server will have three external dependencies.

The first one is obviously express. Express is a framework, that makes creating API very easy.To install express, you can use this command inside of the server directory:

npm install express

Because we want to access the API from a react application that is probably served from another origin, the server needs to allow cross-origin requests.Therefore we are going to use a simple module called CORS.To install it, type:

npm install cors

Also, express itself is not very good at understanding forms. Because we will be uploading our files in the multipart/form-data format, we need to be able to parse this format.The library "formidable" does this and is quite easy to use.Install formidable using this command:

npm install formidable

That's all we need. Now it is time to start building our file upload server...

Setting up a basic express server

First, we need to create a basic express server in the server.js file. This part looks always the same and consists of only 3 lines.

Implementing the upload route

Let's start implementing the upload functionality. We will place it into the upload.js file.

First, we need to require a class called IncomingForm from the "formidable" library.

server/upload.js

const IncomingForm = require('formidable').IncomingForm;

After that, we need to export the callback function, we are using in our server.js to register the route. This function will be called, every time somebody hits the '/upload' URL.This callback gives us a request-object (req), that stores information about the request that hit the route.

We also get a response-object (res). We can use this object, to send back a response.

server/upload.js

module.exports = functionupload(req, res) {
};

Inside of that method, we create a new form.

server/upload.js

var form = newIncomingForm();

We then register callbacks on that form. The first callback is called for every file in the form:

server/upload.js

form.on('file', (field, file) => {// Do something with the file// e.g. save it to the database// you can access it using file.path});

The uploaded files are stored in a temporary directory somewhere on your machine. To do something with them, you can copy them from there using the node.js file-system API.

The second callback is called when the form is completely parsed. In this case, we want to send back a success status code.

server/upload.js

form.on('end', () => { res.json();});

We then trigger the parsing of the form using:

server/upload.js

form.parse(req);

That's all we will do for the upload functionality. It is not production ready, but it will help us to test our upload-component of the react application we actually want to build.

While we are at it, we can also add the overall layout of the component.

The file upload component will be split into two parts. On the left side will be a file dropzone to add new files, while on the right side there will be the list of files to be uploaded and their respective upload progress.

Finally, on the bottom right there will be an actions-section containing the upload button.

Just as described in the article, our dropzone will be placed inside a directory called "dropzone" under the src-directory. So if you created your dropzone component following that article, you can just copy and paste that folder into this project.

app/src/upload/Upload.js

import Dropzone from"../dropzone/Dropzone";

Afterward, place the dropzone component into the upload component like so:

Afterwards, we pass the progress to the progress component. Additionally you can add an icon that is displayed on the right side of the progress bar, when the upload completed successfully.The visibility of this icon is controlled by its opacity, to avoid an rearrangement of the progress bar.

You can add any icon you want. Just place it in the apps public folder and use the filename in the src-attribute of the image above.

Rendering Actions to upload the files

There is still one section of the user interface, we haven't implemented yet. The action-section containing the button to trigger the upload.

Because the rendering of the button also depends on some conditions, the rendering was extracted to another mehtod called "renderActions".

app/src/upload/Upload.js

...<divclassName="Actions">{this.renderActions()}</div>...

This is because we want the button to have different text and behave in a different way, when the upload completed. In that case, we want the button to clear the file list and reset the components state.

Otherwise, the button should trigger the upload of the files.

Also, the button should be disabled when the file list is empty or the component is currently uploading files:

First of all, we clear any uploadProgress that may be left from a previous upload. Also, we set the uploading-flag to true.

Next, we create an array to hold a promise for each file upload. This array is filled by calling the "sendRequest" method (which we will implement next) for each file, triggering the upload of the file.

Then, we wait until every upload is completed by awaiting .all promises.

Finally, we set the successfullUploaded-flag to true and the uploading-flag to false.

Uploading files to the server using XMLHttpRequest

To upload the files to the server, we implement the "sendRequest" method.

All this method does for now, is creating a new Promise. Inside of that promise, we create a new XMLHttpRequest and send that to the url of our file upload server using a post request and the file to upload wrapped into a FromData object.

Stay up to date about what is going on in the web-dev community and on this site.

Special offers

Get notified about special offers of our own, or our partners' products. Don't worry, we won't spam your inbox!

Your Email Address

Yes, I want to subscribe to the email newsletter about new articles, products and special offers.

You can change your mind at any time by clicking the unsubscribe link in the footer of any email you
receive from us. For more information about our privacy practices, email performance mesurements, logging of the registration
process and your rights, please take a look at our
Privacy Policy

Join the Newsletter

Never miss a post

Receive updates when a new post is published.

Stay in touch

Stay up to date about what is going on in the web-dev community and on this site.

Special offers

Get notified about special offers of our own, or our partners' products. Don't worry, we won't spam your inbox!

Your Email Address

Yes, I want to subscribe to the email newsletter about new articles, products and special offers.

You can change your mind at any time by clicking the unsubscribe link in the footer of any email you
receive from us. For more information about our privacy practices, email performance mesurements, logging of the registration
process and your rights, please take a look at our
Privacy Policy