Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

React Image Upload: How It's Done

DZone 's Guide to

React Image Upload: How It's Done

Learn how to create an app using React, Node, and Express that accepts file inputs, stores the file, and returns the path to the file for rendering.

· Web Dev Zone ·
Free Resource

File upload is a very important feature of web applications: it helps facilitate actions like setting a user's profile picture, setting up dynamic galleries, remote file storage, and file sharing, among many other functionalities. In this article, we will be looking at file upload (more specifically, images), using the React web framework, and a Node.js Express backend server.

Here is the application we are going to be building:

Configuring Our React Development Environment

We're going to use Eclipse and CodeMix to develop our React application. To install CodeMix into your Eclipse environment, please follow the installation instructions on this page.

So let's get started with the React file uploads tutorial. Before proceeding, you have to make sure you have Node and npm (or Yarn) installed on your computer. If you don't have them installed, you can download Node (which comes with npm) from the Node official website and follow the installation instructions.

Also, make sure that react-scripts is installed globally. This can be install ed by executing the following command in the terminal:

<span class=" author-d-1gg9uz65z1iz85zgdz68zmqkz84zo2qovwsz122zaxz122ztiz69zvsz85zz84zz90zz79zz89zx8ez77zcz77zacym2gpz65z1">npm install -g react-scripts</span>

Now we can create our project using the Eclipse IDE by navigating to File > New > Project. Select the React option under the CodeMix list of projects, name the application, and click Next to proceed (make sure you're connected to the Internet to get the newest React template and folder structure for the application).

Image title

Once the process is completed, we can install the required dependencies for our project using Ctrl+Shift+P to open a command terminal. Once the terminal is opened, execute the command below to install all the required packages:

npm n install

Afterwards, we will pull in some modules we would use to build the application, using the command below:

<span class=" author-d-1gg9uz65z1iz85zgdz68zmqkz84zo2qovwsz122zaxz122ztiz69zvsz85zz84zz90zz79zz89zx8ez77zcz77zacym2gpz65z1">npm install --save express cors mul

Before we get started with coding, let's go over a few of the technologies we will be using:

  • Express: A Node.js module which simplifies the creation of a node server.
  • Cors: A Node.js module that provides a middleware to handle cross-origin resource sharing.
  • Multer: A Node.js middleware for handling "multipart/form-data" which is primarily used for uploading files.
  • Axios: A Promise-based HTTP client which we will use to communicate with the Node server.

Let's move on to the development of the application. First, we'll create the server that will have just one route, which will accept the files submitted, save them, and return a path to the files. We do this by creating a file at the root of our project folder called server.js, which contains the server setup, Multer configuration, and the sole route of the application.

This file should look like this:

const express = require('express');
const multer = require('multer');
const cors = require('cors');

const app = express();

app.use(express.static('public'))

var storage = multer.diskStorage({
    destination: (req, file, cb) => {
        cb(null, 'public/images/uploads')
    },
    filename: (req, file, cb) => {
        cb(null, Date.now() + '-' + file.originalname)
    }
});
const upload = multer({
    storage
})

app.use(cors());

app.post('/upload', upload.single('image'), (req, res) => {
    if (req.file)
        res.json({
            imageUrl: `images/uploads/${req.file.filename}`
        });
    else
        res.status("409").json("No Files to Upload.");
});

const PORT = 5000;

app.listen(PORT);
console.log('api runnging on port: ' + PORT);

The first section of this code loads all the modules we'll be using in setting up our Express backend. It also instructs Express to load all the files in the public directory into the root directory of the project (that is, it exposes them to be rendered through a call to the file path from the root URL).

Next, we set up the configuration for the multer middleware, telling multer how and where to store received files. In our case, we are saving them in the public/images/uploads directory. Then we instantiate a multer object, passing to it the configuration which we created.

Afterwards, we create the route to which the image will be posted (this is done after we enabled the CORS middleware). On the route definition, we pass the multer middleware, which expects a single file upload. We then return the file path as response data to the caller or return an error if no file is found.

We then run the server on the given port. To run the server, we have to include an entry in the package.json file in the scripts array.

<span class=" author-d-1gg9uz65z1iz85zgdz68zmqkz84zo2qovwsz122zaxz122ztiz69zvsz85zz84zz90zz79zz89zx8ez77zcz77zacym2gpz65z1">"server": "node server.js"</span>

This will enable us to run the server from the terminal, using the following command in the project directory. After that, we can proceed to build our React application to use the server we created.

<span class=" author-d-1gg9uz65z1iz85zgdz68zmqkz84zo2qovwsz122zaxz122ztiz69zvsz85zz84zz90zz79zz89zx8ez77zcz77zacym2gpz65z1">npm run server</span>

We proceed by creating a file, app.js which will contain our application's main component.

Given the template provided by CodeMix, we'll have an index.js which is the entry point the application. Here we will import our App component and render it.


The index.js should look like this:

import ReactDOM from 'react-dom';
import App from './App';

ReactDOM.render(<App />, document.getElementById('root'));

Now we can proceed to implement the React part of this application. The app.js  file should contain the code below:

import React, { Component } from 'react';
import axios from 'axios';
const BASE_URL = 'http://localhost:5000/';

class App extends Component {
constructor(props) {
super(props);
this.state = {
images: [],
imageUrls: [],
message: ''
}
}
selectImages = (event) => {
let images = []
for (var i = 0; i < event.target.files.length; i++) {
images[i] = event.target.files.item(i);
}
images = images.filter(image => image.name.match(/\.(jpg|jpeg|png|gif)$/))
let message = `${images.length} valid image(s) selected`
this.setState({ images, message })
}

uploadImages = () => {
const uploaders = this.state.images.map(image => {
const data = new FormData();
data.append("image", image, image.name);

// Make an AJAX upload request using Axios
return axios.post(BASE_URL + 'upload', data)
.then(response => {
this.setState({
imageUrls: [ response.data.imageUrl, ...this.state.imageUrls ]
});
})
});

// Once all the files are uploaded 
axios.all(uploaders).then(() => {
console.log('done');
}).catch(err => alert(err.message));
}

render() {
return (
<div>
<br/>
<div className="col-sm-12">
<h1>Image Uploader</h1><hr/>
<div className="col-sm-4">
<input className="form-control " type="file" 
onChange={this.selectImages} multiple/>
</div>
<p className="text-info">{this.state.message}</p>
<br/><br/><br/>
<div className="col-sm-4">
<button className="btn btn-primary" value="Submit" 
onClick={this.uploadImages}>Submit</button>
</div>
</div>
<br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><hr/><br/>
<div className="row col-lg-12">
{ 
this.state.imageUrls.map((url, i) => (
<div className="col-lg-2" key={i}>
<img src={BASE_URL + url} className="img-rounded img-responsive"
alt="not available"/><br/>
</div>
))
}
</div>
</div>
);
}
}
export default App;

In the constructor, we initialize the state object of the component. Next, we define the selectImages method which is triggered by the event of the file input field. Here we loop through the FileList object received from the input field, validating and checking to make sure that the files are images (using a property on each file called "name" in a regular expression match check) and adding the results to the images property on the state object.

Next, we define uploadImages, which is triggered by the event on the submit button. This method loops through the images array in the component state (creating a form containing the next image to be uploaded), sends them as a post request using axios to the upload URL, and, finally, saves each file URL received to the imageUrls array in the state. We then handle the event of completion of all uploads using the method on the array of promises returned to the uploaders handle.

Finally, we render each of the images uploaded, using the array of file paths in the object in the state object.


Conclusion

In this article, we discussed how to create a Node Express backend that accepts file inputs, stores the file, and returns the path to the file for rendering. We also covered interaction with a server which we created using the React framework. The method used performs adequately for both single and multiple file (image) uploads.

We also took advantage of the various features presented to us by CodeMix, including application scaffolding, syntax highlighting, and code snippets throughout the development of this application.

The code for this application can be downloaded here.

Topics:
web dev ,react.js ,node.js ,express ,web application development

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}