Click here to Skip to main content
15,890,557 members
Articles / All Topics

Your First App using React with Express and MongoDB

Rate me:
Please Sign up or sign in to vote.
5.00/5 (2 votes)
1 Mar 2017CPOL2 min read 26.3K   2   1
Your first App using React with Express and MongoDB

In one of our previous MEAN Stack tutorials, we followed a step by step approach to develop a RESTful API using ExpressJS with MongoDB. Here in this MEAN Stack article, we are going to develop another application in ExpressJS and MongoDB with ReactJS. We will follow the same step by step approach to build this application.

Now, let's move further to start developing our application using ReactJs with Express and MongoDB.

STEP 1: Initialize the Project

  • Create a folder with the project name such as todoapp.
  • Open command prompt window on the project folder.
  • Run the following command:
    npm init
    This command will create a package.json file with the following details:

    MEAN Stack Tutorial

STEP 2: Install Express

  • Install express with following command:
    npm install express --save

STEP 3: Install Express Generator

  • Install express-generator using the following command:
    npm install express-generator --save

STEP 4: Create the Project

  • Use the following command to create the express project:
    express hello-mern

    This will give the following output:

    create : todoapp
       create : todoapp/package.json
       create : todoapp/app.js
       create : todoapp/public
       create : todoapp/routes
       create : todoapp/routes/index.js
       create : todoapp/routes/users.js
       create : todoapp/views
       create : todoapp/views/index.jade
       create : todoapp/views/layout.jade
       create : todoapp/views/error.jade
       create : todoapp/public/stylesheets
       create : todoapp/public/stylesheets/style.css
       create : todoapp/public/javascripts
       create : todoapp/public/images
       create : todoapp/bin
       create : todoapp/bin/www
     
       install dependencies:
         $ cd hellomern && npm install
     
       run the app:
         $ DEBUG=hellomern ./bin/www

STEP 5: Setup Development Dependencies

  • Add the following dependencies and dev dependencies in package.json file and run npm install from the root folder of the project.
    {
      "name": "hello-mern",
      "version": "0.0.0",
      "private": true,
      "scripts": {
        "start": "webpack --progress --colors --watch -d",
        "build": "webpack --progress --colors -p"
      },
      "dependencies": {
        "axios": "^0.15.3",
        "babel-cli": "^6.11.4",
        "babel-core": "^6.13.2",
        "babel-preset-es2015": "^6.13.2",
        "babel-preset-react": "^6.11.1",
        "body-parser": "~1.16.0",
        "cookie-parser": "~1.4.3",
        "debug": "~2.6.0",
        "ejs": "^2.5.6",
        "express": "~4.14.1",
        "jade": "~1.11.0",
        
        "mongojs": "^2.4.0",
      
        "morgan": "~1.7.0",
        "react": "^15.4.2",
        "react-bootstrap": "^0.30.7",
        "react-dom": "^15.4.2",
        "react-router": "^2.6.1",
        "serve-favicon": "~2.3.2"
      },
      "devDependencies": {
        "babel-loader": "^6.2.10",
        "http-server": "^0.9.0",
        "webpack": "^1.13.3"
      }
    }

STEP 6: Setup ReactJs Build Dependencies:

  • In package.json, add the following script and dev-dependencies.
    JavaScript
    "scripts": {
      "start": "node ./bin/www",
      "start": "webpack --progress --colors --watch -d",
      "build": "webpack --progress --colors -p"
    },
    "devDependencies": {
      "babel-loader": "^6.2.10",
      "http-server": "^0.9.0",
      "webpack": "^1.13.3"
    }
  • Config the webpack.config.js file as follows:
    JavaScript
    var webpack = require('webpack');
    
    var definePlugin = new webpack.DefinePlugin({
        __DEV__: JSON.stringify(JSON.parse(process.env.BUILD_DEV || 'true')),
        __PRERELEASE__: JSON.stringify(JSON.parse(process.env.BUILD_PRERELEASE || 'false'))
    });
    var commonsPlugin = new webpack.optimize.CommonsChunkPlugin('common.js');
    module.exports = {
        cache: true,
        entry: {      main:  './views/index.jsx'   },
        output: {    path: 'public/build',        filename: '[name].js'    },
        module: {
            loaders: [
                {test: /\.jsx?$/, loader: 'babel', 
                exclude: /(node_modules|bower_components)/, query: { presets: ['react', 'es2015'] }},
            ]
        },
        resolve: {
            extensions: ['', '.js', '.jsx']
        },
        plugins: [
            definePlugin,
            commonsPlugin
        ]
    };
  • From command prompt, run 'npm start'. This will create a new directory called build inside public folder. and the following files will be there:

    npm start

  • Create index.html file inside public folder.
    HTML
    <!doctype html>
    <html lang="en">
      <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
    
        <title>MERN</title>
        <meta name="viewport" content="width=device-width">
        <link rel="stylesheet" href="./stylesheets/style.css" />
        <link rel="stylesheet" href="./stylesheets/App.css" />
        <script src="./build/common.js"></script>
    
      </head>
      <body>
      <div id="root"></div>
      <script src="./build/main.js"></script>
    
      </body>
    </html>
  • Change the routes in routes/index.js as follows:
    JavaScript
    var express = require('express');
    var router = express.Router();
    
    /* GET home page. */
    router.get('/', function(req, res, next) {
     // res.render('index', { title: 'Express'}); this is the old line
      res.render('index.html');
    });
    
    module.exports = router;
  • Change the app-engine in app.js.
    JavaScript
    // view engine setup
    app.set('views', path.join(__dirname, 'views'));
    app.set('view engine', 'ejs'); 
    app.engine('html', require('ejs').renderFile);
  • Create an index.jsx in /views folder:
    JavaScript
    import React from 'react';
    import ReactDOM from 'react-dom';
    import App from './App';
    
    
    ReactDOM.render(
      <App />,
      document.getElementById('root')
    );
  • Create a App.jsx in /views folder:
    import React, { Component } from 'react';
    
    
    
    class App extends Component {
      render() {
        return (
          <div className="App">
            <div className="App-header">
              <img src="./images/logo.svg" className="App-logo" alt="logo" />
              <h2>Welcome to React+ Express +Mongo</h2>
            </div>
          </div>
        );
      }
    }
    
    export default App;
  • From browser, run http://localhost:3000/:MEAN Stack App

STEP 7: Run Mongo

  • Run mongodb.exe - it will start the mongodb.

    Run MongoDB Tutorial

  • Connect to todoapp database using the following command:

    Connect MongoDB

STEP 8: Develop the Server-side

  • Create the server REST API in routes/todo.js:
    JavaScript
    var express = require('express');
    var router = express.Router();
    var mongojs = require('mongojs');
    var db = mongojs('mongodb://localhost:27017/todoapp', ['todos']);
    
    // Get All todos
    router.get('/todos', function(req, res, next){
        db.todos.find(function(err, todos){
            if(err){
                res.send(err);
            }
            res.json(todos);
        });
    });
    
    // Get Single Task
    router.get('/todo/:id', function(req, res, next){
        db.todos.findOne({_id: mongojs.ObjectId(req.params.id)}, function(err, todo){
            if(err){
                res.send(err);
            }
            res.json(todo);
        });
    });
    
    //Save todo
    router.post('/new', function(req, res, next){
        var todo = req.body;
        if(!todo.title || !(todo.isDone + '')){
            res.status(400);
            res.json({
                "error": "Bad Data"
            });
        } else {
            db.todos.save(todo, function(err, todo){
                if(err){
                    res.send(err);
                }
                res.json(todo);
            });
        }
    });
    
    // Delete todo
    router.delete('/todo/:id', function(req, res, next){
        db.todos.remove({_id: mongojs.ObjectId(req.params.id)}, function(err, todo){
            if(err){
                res.send(err);
            }
            res.json(todo);
        });
    });
    
    // Update todo
    router.put('/todo/:id', function(req, res, next){
        var todo = req.body;
        var updtodo = {};
    
        if(todo.isDone){
            updtodo.isDone = todo.isDone;
        }
    
        if(todo.title){
            updtodo.title = todo.title;
        }
    
        if(!updtodo){
            res.status(400);
            res.json({
                "error":"Bad Data"
            });
        } else {
            db.todos.update({_id: mongojs.ObjectId(req.params.id)},updtodo, {}, function(err, todo){
                if(err){
                    res.send(err);
                }
                res.json(todo);
            });
        }
    });
    
    module.exports = router;

STEP 9: Develop the Client-side

  • Add model:
    JavaScript
    //mode/todo.js
    'use strict';
    //import dependency
    var mongoose = require('mongoose');
    var Schema = mongoose.Schema;
    
    //create new instance of the mongoose.schema. the schema takes an object that shows
    //the shape of your database entries.
    var TodoSchema = new Schema({
      title: String,
      description: String,
      priority: String,
      duedate: String,
      status: String
    
    });
    
    //export our module to use in server.js
    module.exports = mongoose.model('Todo', TodoSchema);
  • Add Form Component 'TodoForm'.
    JavaScript
    import React, { Component } from 'react';
    import style from './style';
    
    export default  class TodoForm extends Component {
        constructor(props) {
            super(props);
            this.state = { author: '', text: '' };
    
            this.handleSubmit = this.handleSubmit.bind(this);
        }
    
        handleSubmit(e) {
            e.preventDefault();
            let author = this.state.author.trim();
            let text = this.state.text.trim();
            if (!text || !author) {
                return;
            }
            this.props.onCommentSubmit({ author: author, text: text });
            this.setState({ author: '', text: '' });
        }
        render() {
            return (
    
           <div>
                <h1> Add new Todo</h1>
                <form  onSubmit={ this.handleSubmit }>
                    <div className="form-group">
                        <label for="exampleInputEmail1">Title</label>
                        <input type="text" className="form-control" 
                         id="exampleInputEmail1" 
                         aria-describedby="emailHelp" 
                         placeholder="Title"/>
    
                    </div>
                    <div className="form-group">
                        <label for="exampleSelect1">Priority</label>
                        <select className="form-control" 
                        id="exampleSelect1">
                            <option>High</option>
                            <option>Medium</option>
                            <option>Normal</option>
    
                        </select>
                    </div>
                    <div className="form-group">
                        <label for="exampleTextarea">Description</label>
                        <input type="text" className="form-control" 
                         id="exampleTextarea"placeholder="Description"/>
                    </div>
                    <div className="form-group">
                        <label for="datetimepicker1">Due date</label>
                        <div className='input-group date' id='datetimepicker1'>
                            <input type='text' className="form-control" />
                            <span className="input-group-addon">
                            <span className="glyphicon glyphicon-calendar"></span>
                        </span>
                        </div>
                    </div>
                    <button type="submit" className="btn btn-primary">Add</button>
                    <button type="cancel" className="btn btn-danger">Cancel</button>
                </form>
               </div>
            )
        }
    }
  • Add List Component:
    JavaScript
    import React, { Component } from 'react';
    
    
    export default class TodoList extends Component {
        render() {
            let todoNodes = this.props.data.map(todo => {
                return (
                    <div className="panel panel-primary">
                        Title : {todo.title}
                    </div>
                )
            })
            return (
    
                <div className="panel panel-success">
                    <h1> All Todos </h1>
                    { todoNodes }
                </div>
            )
        }
    }
  • Update App.jsx:
    JavaScript
    import React, { Component } from 'react';
    import style from './style';
    import TodoForm from './TodoForm';
    import TodoList from './TodoList';
    
    import axios from 'axios';
    
    class App extends Component {
    
        constructor(props) {
            super(props);
            this.state = { data: [] };
            this.loadTodosFromServer = this.loadTodosFromServer.bind(this);
            this.handleTodoSubmit = this.handleTodoSubmit.bind(this);
            this.handleTodoDelete = this.handleTodoDelete.bind(this);
            this.handleTodoUpdate = this.handleTodoUpdate.bind(this);
        }
        loadTodosFromServer() {
            axios.get(this.props.url)
                .then(res => {
                    this.setState({ data: res.data });
                })
        }
        handleTodoSubmit(comment) {
            let comments = this.state.data;
            comment.id = Date.now();
            let newComments = comments.concat([comment]);
            this.setState({ data: newComments });
            axios.post(this.props.url+'/todo/'+comment.id, comment)
                .catch(err => {
                    console.error(err);
                    this.setState({ data: comments });
                });
        }
        handleTodoDelete(id) {
            axios.delete(`${this.props.url}/${id}`)
                .then(res => {
                    console.log('Comment deleted');
                })
                .catch(err => {
                    console.error(err);
                });
        }
        handleTodoUpdate(id, comment) {
            //sends the comment id and new author/text to our api
            axios.put(`${this.props.url}/${id}`, comment)
                .catch(err => {
                    console.log(err);
                })
        }
        componentDidMount() {
            this.loadTodosFromServer();
            setInterval(this.loadTodosFromServer, this.props.pollInterval);
        }
    
    
       render() {
        return (
          <div className="App">
            <div className="App-header">
              <img src="./images/logo.svg" 
              className="App-logo" alt="logo" />
              <h2>Welcome to React+ Express +Mongo</h2>
            </div>
              <TodoList
                  onTodoDelete={ this.handleTodoDelete }
                  onTodoUpdate={ this.handleTodoUpdate }
                  data={ this.state.data }/>
              <TodoForm onTodoSubmit={ this.handleTodoSubmit }/>
    
    
          </div>
        );
      }
    }
    
    export default App;
  • Update index.jsx:
    JavaScript
    import React from 'react';
    import ReactDOM from 'react-dom';
    import App from './App';
    
    ReactDOM.render(
      <App url='http://localhost:3000/todos'
           pollInterval={2000}/>,
      document.getElementById('root')
    );
  • From browser:

    ReactJS Application

Hopefully, this application will be helpful in understanding the technology in a practical manner and developing the first application using React.js with Express and MongoDB.

Top Related Technical Articles

The post Your first App using React with Express and MongoDB appeared first on Web Development Tutorial.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) Emaratech
United Arab Emirates United Arab Emirates
Imran Abdul Ghani has more than 10 years of experience in designing/developing enterprise level applications. He is Microsoft Certified Solution Developer for .NET(MCSD.NET) since 2005. You can reach his blogging at WCF Tutorials, Web Development, SharePoint for Dummies.

Comments and Discussions

 
Questionhello-mern Pin
jxb0429-Nov-18 9:21
jxb0429-Nov-18 9:21 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.