65.9K
CodeProject is changing. Read more.
Home

Your First App using React with Express and MongoDB

starIconstarIconstarIconstarIconstarIcon

5.00/5 (2 votes)

Mar 2, 2017

CPOL

2 min read

viewsIcon

26482

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.
    "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:
    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.
    <!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:
    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.
    // 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:
    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:
    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:
    //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'.
    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:
    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:
    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:
    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.