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:
STEP 2: Install Express
STEP 3: Install Express Generator
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:
- 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();
router.get('/', function(req, res, next) {
res.render('index.html');
});
module.exports = router;
- Change the
app-engine
in app.js.
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/:
STEP 7: Run Mongo
- Run mongodb.exe - it will start the mongodb.
- Connect to
todoapp
database using the following command:
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']);
router.get('/todos', function(req, res, next){
db.todos.find(function(err, todos){
if(err){
res.send(err);
}
res.json(todos);
});
});
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);
});
});
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);
});
}
});
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);
});
});
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:
'use strict';
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var TodoSchema = new Schema({
title: String,
description: String,
priority: String,
duedate: String,
status: String
});
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) {
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:
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
CodeProject
The post Your first App using React with Express and MongoDB appeared first on Web Development Tutorial.