React 18 Single File Upload Tutorial with Multer, Node, Express

Last Updated on by in React JS
In this tutorial, we will learn how to upload a single image file in React using React hooks, functional component and Express REST APIs.We will also focus on how to create Node server from absolute beginning and store image files in the MongoDB database using the Multer and express.

Uploading image files is a routine task for a web developer, if you are new to React, then this tutorial has the answer which you are looking for.

We will learn to upload single image file and store that file in the MongoDB database using Node and React.js.

We will learn to create a client-side basic React app, along with that we will also create a file upload API with Express, Multer, and other Node packages.

React Node Multer File Upload Example

  • Step 1: Install React App
  • Step 2: Create React File Upload Component
  • Step 3: Create File Upload API
  • Step 4: Create Schema
  • Step 5: Define Express Routes
  • Step 6: Set up Node Server
  • Step 7: Test React File Upload API
  • Step 8: Build React Single File Upload

React 18 File Upload with Node Server

In the very first step, we install and set up React app for file upload demo.

Install React App

Enter the following command in your terminal and press enter.

npx create-react-app react-node-file-upload

Go to the project folder:

cd react-node-file-upload

Install Bootstrap in React app.

npm install bootstrap --legacy-peer-deps

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

Create React File Upload Component

Head over to src > components directory and create a separate file by the name of files-upload-component.js.

import React, { Component } from "react";
export default class FilesUploadComponent extends Component {
  render() {
    return (
      <div className="container">
        <div className="row">
          <form>
            <h3>React File Upload</h3>
            <div className="mb-3">
              <input type="file" className="form-control" />
            </div>
            <div>
              <button className="btn btn-primary" type="submit">
                Upload
              </button>
            </div>
          </form>
        </div>
      </div>
    );
  }
}

Add FilesUploadComponent in src/App.js template.

import React from "react";
import "../node_modules/bootstrap/dist/css/bootstrap.min.css";
import "./App.css";
import FilesUploadComponent from "./components/files-upload-component";
function App() {
  return (
    <div className="container w-50 p-3">
      <FilesUploadComponent />
    </div>
  );
}
export default App;

React File Upload

Create File Upload API

We will use the Node, Express, MongoDB and Multer for creating the File upload REST API, this will helps us better comprehend the React file upload tutorial.

Create the backend folder inside the React project.

Build separate package.json file for Node server.

npm init -y

We will use following node modules to build Node/Express server:

NPMDetail
ExpressA web application framework for Node.js.
MongoDBNoSQL Database based on document and collection format.
CORSSupports Access-Control-Allow-Origin CORS header.
bodyParserA body parsing middleware for Node.js.
uuidSimple, fast generation of RFC4122 UUIDS.
MulterA Node.js middleware handles multipart/form-data, best used of file uploading.

Run command to install NPM packages:

npm install mongoose express cors body-parser uuid@^3.4.0 multer --legacy-peer-deps

Install nodemon to auto-restart the node server, whenever it detects change in the server files.

Create Schema

Create a backend > models directory and create a fresh file inside of it and name it User.js.

const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const userSchema = new Schema({
    _id: mongoose.Schema.Types.ObjectId,
    profileImg: {
        type: String
    }
}, {
    collection: 'users'
})
module.exports = mongoose.model('User', userSchema)

We declared profileImg value with String data type along with Mongoose _id in Mongoose schema file.

Define Express Routes

Create a backend > routes folder and create a new file inside of it and name it user.routes.js.

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('/user-profile', upload.single('profileImg'), (req, res, next) => {
    const url = req.protocol + '://' + req.get('host')
    const user = new User({
        _id: new mongoose.Types.ObjectId(),
        name: req.body.name,
        profileImg: url + '/public/' + req.file.filename
    });
    user.save().then(result => {
        res.status(201).json({
            message: "User registered successfully!",
            userCreated: {
                _id: result._id,
                profileImg: result.profileImg
            }
        })
    }).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;

Create backend/public folder, in this folder we will store all the image files uploaded by user.

Set up Node Server

In this step, create a backend > index.js file and paste the following code in it. This file contains required server settings such as database, express configuration, PORT connection, etc.

let express = require("express"),
  mongoose = require("mongoose"),
  cors = require("cors"),
  bodyParser = require("body-parser");
const api = require("../backend/routes/user.routes");
// Connecting mongoDB Database
mongoose
  .connect("mongodb://127.0.0.1:27017/test")
  .then((x) => {
    console.log(
      `Connected to Mongo! Database name: "${x.connections[0].name}"`,
    );
  })
  .catch((err) => {
    console.error("Error connecting to mongo", err.reason);
  });
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 File Upload API

In this step we will test REST API which we just created, before that we need to start the Node server.

Follow the given below process to start the Node/Express server.

Check out how to install MongoDB community edition on your local machine.

Run nodemon server by executing the following command:

npx nodemon server
MethodAPI URL
GEThttp://localhost:4000/api
POST/api/user-profile

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

We can test following API in Postman, below is the final result:

React File Upload API Testing

Build React Single File Upload

Let’s build React File upload functionality, first install the React axios library.

Next, install Axios library, it helps in making Http request in React app.

npm install axios --legacy-peer-deps

Add the below code in src/components/files-upload.component.js file.

import React, { useState } from "react";
import axios from "axios";
export default function FilesUploadComponent() {
  const [profileImg, setProfileImg] = useState("");
  const [isFileUploaded, setIsFileUploaded] = useState(false);
  const onFileChange = (e) => {
    setProfileImg(e.target.files[0]);
  };
  const onSubmit = (e) => {
    e.preventDefault();
    const formData = new FormData();
    formData.append("profileImg", profileImg);
    axios
      .post("http://localhost:4000/api/user-profile", formData, {})
      .then((res) => {
        console.log(res);
        setIsFileUploaded(true);
      });
  };
  return (
    <div className="container">
      <h2 className="mb-3">React 18 Node Image File Upload Example</h2>
      <form onSubmit={onSubmit}>
        <div className="mb-3">
          <input type="file" className="form-control" onChange={onFileChange} />
        </div>
        <button className="btn btn-primary" type="submit">
          Upload
        </button>
      </form>
      {isFileUploaded && (
        <div className="alert alert-success mt-3">
          File successfully uploaded!
        </div>
      )}
    </div>
  );
}

Declare the state and set the profileImg state using the useState hook in function component.

Inside the file input field, we passed the onChange event along with onSubmit method on the form.

In the onSubmit method, manage the file value using FormData interface, then make the axios HTTP POST request method to upload the file onto the node server and REST API..

Start your React app in the web browser:

npm start

View project on this URL: localhost:3000

react-file-upload-6559-02

Conclusion

Finally, React File Upload with Node/Express Js Tutorial is over.

In this tutorial, we learned to upload a single file in React app and store the images in the MongoDB database using the Node server.

Digamber - Author positronX.io

Hi, I'm Digamber Singh, a New Delhi-based full-stack developer, tech author, and open-source contributor with 10+ years' experience in HTML, CSS, JavaScript, PHP, and WordPress.