React Multiple Files Upload with Node/Express Tutorial

By Digamber Rawat Last updated on
We are going to discuss mostly talked about topic React Multiple Files Upload with Node/Express Js. In this tutorial, we are going to learn how to upload multiple image files using Node, Express, Multer, and MongoDB. If you are new to React and want to learn how to upload files, then follow along.

We will learn to upload multiple image files and store those files in the MongoDB database using Multer and React. We will create express REST API which a user can easily use to make a POST request using React Axios.

React Multiple Files Upload with Node/Express Server

Let’s, install React app for uploading multiple files .

Set up Basic React Project

Run command from your terminal to install React app.

npx create-react-app react-multiple-files-upload

Go to the project folder:

cd react-multiple-files-upload

Run the app in browser:

npm start

View project on this URL: localhost:3000

Install and set up Bootstrap 4:

npm install bootstrap --save

Include bootstrap.min.css in src/App.js file:

import React from 'react';
import '../node_modules/bootstrap/dist/css/bootstrap.min.css';
import './App.css';

class App extends Component {
  render() {
    return (
      <div className="App">
         <h2>React Multiple Files Upload Example</h2>
      </div>
    );
  }
}

export default App;

Create Multiple File Upload Component

Navigate to src > components folder and create files-upload-component.js file here.

import React, { Component } from 'react';

export default class FilesUploadComponent extends Component {
    render() {
        return (
            <div className="container">
                <div className="row">
                    <form>
                        <h3>React Multiple File Upload</h3>
                        <div className="form-group">
                            <input type="file" multiple/>
                        </div>
                        <div className="form-group">
                            <button className="btn btn-primary" type="submit">Upload</button>
                        </div>
                    </form>
                </div>
            </div>
        )
    }
}

Include FilesUploadComponent in src/App.js file.

import React, { Component } from 'react';
import '../node_modules/bootstrap/dist/css/bootstrap.min.css';
import './App.css';
import FilesUploadComponent from './components/files-upload-component';

class App extends Component {
  render() {
    return (
      <div className="App">
        <FilesUploadComponent />
      </div>
    );
  }
}

export default App;

React Multiple Files Upload

Build Node/Express Server

Build node and express server with CORS, UUID, bodyParser. Create the backend folder inside the React app.

mkdir backend && cd backend

Create specific package.json file for Node/Express server.

npm init

Install NPM modules:

npm install mongoose express cors body-parser uuid multer

Install nodemon package to restart the node server automatically. If any change occurs in server files.

npm install nodemon --save-dev

MongoDB Database Set up

Make backend > database directory and create db.js file in it.

module.exports = {
   db: 'mongodb://localhost:27017/reactdatabase'
};

Create Mongoose Schema

Create backend > models folder and create User.js file in it.

const mongoose = require('mongoose');
const Schema = mongoose.Schema;

const userSchema = new Schema({
    _id: mongoose.Schema.Types.ObjectId,
    imgCollection: {
        type: Array
    }
}, {
    collection: 'users'
})

module.exports = mongoose.model('User', userSchema)

Define imgCollection value with Array data type with Mongoose _id.

Build Express Routes

Create backend > routes directory and create user.routes.js file in it.

We also need to create backend > public folder to store the uploaded image files.

mkdir public
let express = require('express'),
    multer = require('multer'),
    mongoose = require('mongoose'),
    uuidv4 = require('uuid/v4'),
    router = express.Router();

const DIR = './public/';

const storage = multer.diskStorage({
    destination: (req, file, cb) => {
        cb(null, DIR);
    },
    filename: (req, file, cb) => {
        const fileName = file.originalname.toLowerCase().split(' ').join('-');
        cb(null, uuidv4() + '-' + fileName)
    }
});

var upload = multer({
    storage: storage,
    fileFilter: (req, file, cb) => {
        if (file.mimetype == "image/png" || file.mimetype == "image/jpg" || file.mimetype == "image/jpeg") {
            cb(null, true);
        } else {
            cb(null, false);
            return cb(new Error('Only .png, .jpg and .jpeg format allowed!'));
        }
    }
});

// User model
let User = require('../models/User');

router.post('/upload-images', upload.array('imgCollection', 6), (req, res, next) => {
    const reqFiles = [];
    const url = req.protocol + '://' + req.get('host')
    for (var i = 0; i < req.files.length; i++) {
        reqFiles.push(url + '/public/' + req.files[i].filename)
    }

    const user = new User({
        _id: new mongoose.Types.ObjectId(),
        imgCollection: reqFiles
    });

    user.save().then(result => {
        res.status(201).json({
            message: "Done upload!",
            userCreated: {
                _id: result._id,
                imgCollection: result.imgCollection
            }
        })
    }).catch(err => {
        console.log(err),
            res.status(500).json({
                error: err
            });
    })
})

router.get("/", (req, res, next) => {
    User.find().then(data => {
        res.status(200).json({
            message: "User list retrieved successfully!",
            users: data
        });
    });
});

module.exports = router;

Main Server File Setup

Next, create server.js file inside backend folder and paste the given below code inside of it.

let express = require('express'),
    mongoose = require('mongoose'),
    cors = require('cors'),
    bodyParser = require('body-parser'),
    dbConfig = require('./database/db');

const api = require('../backend/routes/user.routes')

mongoose.Promise = global.Promise;
mongoose.connect(dbConfig.db, {
    useNewUrlParser: true,
    useUnifiedTopology: true
}).then(() => {
    console.log('Database sucessfully connected')
},
    error => {
        console.log('Database could not be connected: ' + error)
    }
)

const app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
    extended: false
}));
app.use(cors());

app.use('/public', express.static('public'));

app.use('/api', api)

const port = process.env.PORT || 4000;
const server = app.listen(port, () => {
    console.log('Connected to port ' + port)
})

app.use((req, res, next) => {
    // Error goes via `next()` method
    setImmediate(() => {
        next(new Error('Something went wrong'));
    });
});

app.use(function (err, req, res, next) {
    console.error(err.message);
    if (!err.statusCode) err.statusCode = 500;
    res.status(err.statusCode).send(err.message);
});

Test React Multiple Files Upload API

We are using Postman API testing tool to test our freshly built APIs.

But before that, let’s start the Node server.

Start mongoDB.

mongod

Start nodemon:

nodemon server
Method API URL
GET http://localhost:4000/api
POST /api/upload-images

API base Url: http://localhost:4000/api

Final API result:

Upload API Testing

Create React Multiple Images Upload

Let’s create React multiple image files uploading functionality in React. We need to install axios.

npm install axios

Insert following code in src/components/files-upload.component.js file.

import React, { Component } from 'react';
import axios from 'axios';

export default class FilesUploadComponent extends Component {

    constructor(props) {
        super(props);

        this.onFileChange = this.onFileChange.bind(this);
        this.onSubmit = this.onSubmit.bind(this);

        this.state = {
            imgCollection: ''
        }
    }

    onFileChange(e) {
        this.setState({ imgCollection: e.target.files })
    }

    onSubmit(e) {
        e.preventDefault()

        var formData = new FormData();
        for (const key of Object.keys(this.state.imgCollection)) {
            formData.append('imgCollection', this.state.imgCollection[key])
        }
        axios.post("http://localhost:4000/api/upload-images", formData, {
        }).then(res => {
            console.log(res.data)
        })
    }

    render() {
        return (
            <div className="container">
                <div className="row">
                    <form onSubmit={this.onSubmit}>
                        <div className="form-group">
                            <input type="file" name="imgCollection" onChange={this.onFileChange} multiple />
                        </div>
                        <div className="form-group">
                            <button className="btn btn-primary" type="submit">Upload</button>
                        </div>
                    </form>
                </div>
            </div>
        )
    }
}

React multiple files upload

Conclusion

Finally, React Multiple File Upload with Node/Express Tutorial is over. In this tutorial, we explored how to upload a multiple image files in the MongoDB database using the Node and Express server.

Git Repo

Digamber Rawat
Digamber Rawat

Full stack developer with a passion for UI/UX design. I create beautiful and useful digital products to solve people’s problem and make their life easy.