Here is the step-by-step guide for creating an application that uses React, Node.js, and express server.
Step 1: Install React using create react app.
npx create-react-app react-express-tutorial
After installing, go into that directory.
cd react-express-tutorial
Start the development server.
yarn start
Step 2: Define the routing of components.
Type the following command in your terminal to install the react-router-dom module.
yarn add react-router-dom
It will install the dependency. If you get an error, please install the package manager Yarn. Now, open the code in your favorite editor. I am using Visual Studio Code.
Go to the index.js file and Wrap the BrowserRouter object around the App.js component.
// index.js import React from 'react'; import ReactDOM from 'react-dom'; import App from './App'; import { BrowserRouter } from 'react-router-dom'; import registerServiceWorker from './registerServiceWorker'; ReactDOM.render( <BrowserRouter> <App /> </BrowserRouter>, document.getElementById('root')); registerServiceWorker();
Create one directory called components inside the src folder, and inside that folder, make three components.
- CreateComponent.js
- EditComponent.js
- IndexComponent.js
// CreateComponent.js import React, { Component } from 'react'; export default class CreateComponent extends Component { render() { return ( <div> <p>Welcome to Create Component!!</p> </div> ) } }
// EditComponent.js import React, { Component } from 'react'; export default class EditComponent extends Component { render() { return ( <div> <p>Welcome to Edit Component!!</p> </div> ) } }
// IndexComponent.js import React, { Component } from 'react'; export default class IndexComponent extends Component { render() { return ( <div> <p>Welcome to Index Component!!</p> </div> ) } }
Now, define the routes for each component.
// App.js import React, { Component } from 'react'; import { BrowserRouter as Router, Switch, Route, Link } from 'react-router-dom'; import CreateComponent from './components/CreateComponent'; import EditComponent from './components/EditComponent'; import IndexComponent from './components/IndexComponent'; class App extends Component { render() { return ( <Router> <div> <h2>Welcome to React Express Tutorial</h2> <ul> <li><Link to={'/'}>Home</Link></li> <li><Link to={'/create'}>Create</Link></li> <li><Link to={'/index'}>List</Link></li> <li><Link to={'/edit/:id'}>Edit</Link></li> </ul> <hr /> <Switch> <Route exact path='/create' component={CreateComponent} /> <Route path='/edit/:id' component={EditComponent} /> <Route path='/index' component={IndexComponent} /> </Switch> </div> </Router> ); } } export default App;
Finally, save the file and go to the http://localhost:3000/
Step 3: Include Bootstrap 4 and create a form.
Install Bootstrap 4 using the following command.
yarn add bootstrap@4.0.0
Afterward, go to the index.js file and import the bootstrap as an NPM dependency.
// index.js import React from 'react'; import ReactDOM from 'react-dom'; import App from './App'; import { BrowserRouter } from 'react-router-dom'; import registerServiceWorker from './registerServiceWorker'; import '../node_modules/bootstrap/dist/css/bootstrap.min.css'; ReactDOM.render( <BrowserRouter> <App /> </BrowserRouter>, document.getElementById('root')); registerServiceWorker();
If your development server is running, you can see the bootstrap styles applied to the React Express Application. But, first, give the style to navigation. For that, our code looks like below.
// App.js import React, { Component } from 'react'; import { BrowserRouter as Router, Switch, Route, Link } from 'react-router-dom'; import CreateComponent from './components/CreateComponent'; import EditComponent from './components/EditComponent'; import IndexComponent from './components/IndexComponent'; class App extends Component { render() { return ( <Router> <div className="container"> <nav className="navbar navbar-expand-lg navbar-light bg-light"> <a className="navbar-brand">React Express App</a> <div className="collapse navbar-collapse" id="navbarSupportedContent"> <ul className="navbar-nav mr-auto"> <li className="nav-item"> <Link to={'/'} className="nav-link">Home</Link> </li> <li className="nav-item"> <Link to={'/create'} className="nav-link">Create</Link> </li> <li className="nav-item"> <Link to={'/index'} className="nav-link">Index</Link> </li> <li className="nav-item"> <Link to={'/edit/:id'} className="nav-link">Edit</Link> </li> </ul> </div> </nav> <Switch> <Route exact path='/create' component={CreateComponent} /> <Route path='/edit/:id' component={EditComponent} /> <Route path='/index' component={IndexComponent} /> </Switch> </div> </Router> ); } } export default App;
Apply marignTop: 50 property to all three components.
// CreateComponent.js import React, { Component } from 'react'; export default class CreateComponent extends Component { render() { return ( <div style={{marginTop: 50}}> <p>Welcome to Create Component!!</p> </div> ) } }
Now you can see our design is completely changed.
Create a Bootstrap Form
Write the code to generate the bootstrap form inside the CreateComponent.js file.
// CreateComponent.js import React, { Component } from 'react'; export default class CreateComponent extends Component { render() { return ( <div style={{marginTop: 50}}> <h3>Add New Server</h3> <form> <div className="form-group"> <label>Add Host Name: </label> <input type="text" className="form-control"/> </div> <div className="form-group"> <label>Add Server Port: </label> <input type="text" className="form-control"/> </div> <div className="form-group"> <input type="submit" value="Add Node server" className="btn btn-primary"/> </div> </form> </div> ) } }
Step 4: Submit the Form.
Okay, now we have two fields.
- server name
- server port
So we need to create three functions that can track both the values and set the state according to it. Also, the third function will send the POST request to the node express server.
// CreateComponent.js import React, { Component } from 'react'; export default class CreateComponent extends Component { constructor(props) { super(props); this.onChangeHostName = this.onChangeHostName.bind(this); this.onChangePort = this.onChangePort.bind(this); this.onSubmit = this.onSubmit.bind(this); this.state = { name: '', port: '' } } onChangeHostName(e) { this.setState({ name: e.target.value }); } onChangePort(e) { this.setState({ port: e.target.value }); } onSubmit(e) { e.preventDefault(); console.log(`name is ${this.state.name} and port is ${this.state.port}`); this.setState({ name: '', port: '' }) } render() { return ( <div style={{marginTop: 50}}> <h3>Add New Server</h3> <form onSubmit={this.onSubmit}> <div className="form-group"> <label>Add Host Name: </label> <input type="text" value={this.state.name} className="form-control" onChange={this.onChangeHostName}/> </div> <div className="form-group"> <label>Add Server Port: </label> <input type="text" value={this.state.port} className="form-control" onChange={this.onChangePort}/> </div> <div className="form-group"> <input type="submit" value="Add Node server" className="btn btn-primary"/> </div> </form> </div> ) } }
So, when you submit the form, you can see that we can get both textbox values in the console. So, those values will be sent to the Node.js server and saved into the database.
Step 5: Create a Node.js server and install Express Framework.
Take a break from the front-end part and go to the back-end part of our application. First, inside our project root, create one folder called server. Then, inside the server folder, create one file called server.js. Now, install the express as well as other dependencies.
yarn add express nodemon body-parser cors mongoose
// server.js const express = require('express'); const app = express(); const mongoose = require('mongoose'); const bodyParser = require('body-parser'); const PORT = 4200; const cors = require('cors'); app.use(cors()); app.use(bodyParser.urlencoded({extended: true})); app.use(bodyParser.json()); app.listen(PORT, function(){ console.log('Server is running on Port: ',PORT); });
I have imported all the required packages inside a server.js file.
Okay, now start the Node.js server using the following command.
nodemon server/server
The first server is the folder name, and the second is a server.js file.
You can see in the terminal that the Node js server is running at PORT: 4200.
Step 6: Set up the MongoDB database.
I have already installed MongoDB on Mac. So I am starting the MongoDB server by the following command.
mongod
Also, I need to start the Mongo Shell to interact with the database. So in another tab of the terminal, type the following command to open Mongo Shell.
mongo
Step 7: Connect Express App to Mongo Database.
Inside the server folder, create one folder called the database. Inside the database folder, create one file called DB.js.
// DB.js module.exports = { DB: 'mongodb://localhost:27017/reactexpress' }
My username and password are empty in my local database, but in the production, you need to create one admin user and assign the database to that user.
Now, import this DB.js file into the server.js file.
// server.js const express = require('express'); const app = express(); const mongoose = require('mongoose'); const bodyParser = require('body-parser'); const PORT = 4200; const cors = require('cors'); const config = require('./database/DB'); mongoose.connect(config.DB).then( () => {console.log('Database is connected') }, err => { console.log('Can not connect to the database' +err) }); app.use(cors()); app.use(bodyParser.urlencoded({extended: true})); app.use(bodyParser.json()); app.listen(PORT, function(){ console.log('Server is running on Port: ',PORT); });
Save the file, and see the terminal; you can see that our database is connected with our Express application.
Step 8: Create a Mongoose schema.
Create one folder inside the server folder called models. Then, inside the model’s folder, create one file called ServerPort.js.
// ServerPort.js var mongoose = require('mongoose'); var Schema = mongoose.Schema; // Define collection and schema for Items var ServerPort = new Schema({ name: { type: String }, port: { type: Number } },{ collection: 'servers' }); module.exports = mongoose.model('ServerPort', ServerPort);
Step 9: Create Express routes for the application.
Inside the server folder, create one folder called routes. Then, inside that routes folder, create one file called ServerPortRouter.js.
// ServerPortRouter.js const express = require('express'); const app = express(); const ServerPortRouter = express.Router(); const ServerPort = require('../models/ServerPort'); ServerPortRouter.route('/add').post(function (req, res) { const serverport = new ServerPort(req.body); serverport.save() .then(serverport => { res.json('Server added successfully'); }) .catch(err => { res.status(400).send("unable to save to database"); }); }); ServerPortRouter.route('/').get(function (req, res) { ServerPort.find(function (err, serverports){ if(err){ console.log(err); } else { res.json(serverports); } }); }); ServerPortRouter.route('/edit/:id').get(function (req, res) { const id = req.params.id; ServerPort.findById(id, function (err, serverport){ res.json(serverport); }); }); ServerPortRouter.route('/update/:id').post(function (req, res) { ServerPort.findById(req.params.id, function(err, serverport) { if (!serverport) return next(new Error('Could not load Document')); else { // do your updates here serverport.name = req.body.name; serverport.port = req.body.port; serverport.save().then(serverport => { res.json('Update complete'); }) .catch(err => { res.status(400).send("unable to update the database"); }); } }); }); ServerPortRouter.route('/delete/:id').get(function (req, res) { ServerPort.findByIdAndRemove({_id: req.params.id}, function(err, serverport){ if(err) res.json(err); else res.json('Successfully removed'); }); }); module.exports = ServerPortRouter;
The last step is to import this ServerPortRouter.js file into the server.js file. So the final server.js file looks like below.
// server.js const express = require('express'); const app = express(); const mongoose = require('mongoose'); const bodyParser = require('body-parser'); const PORT = 4200; const cors = require('cors'); const config = require('./database/DB'); const ServerPortRouter = require('./routes/ServerPortRoutes'); mongoose.connect(config.DB).then( () => {console.log('Database is connected') }, err => { console.log('Can not connect to the database' +err) }); app.use(cors()); app.use(bodyParser.urlencoded({extended: true})); app.use(bodyParser.json()); app.use('/serverport', ServerPortRouter); app.listen(PORT, function(){ console.log('Server is running on Port: ',PORT); });
Step 10: Install the Axios library and send the POST request to the server.
We use the Axios library for the network request to the Node.js server. So let’s install it first.
yarn add axios
Send the post request and form data to the node js server.
// CreateComponent.js onSubmit(e) { e.preventDefault(); const serverport = { name: this.state.name, port: this.state.port } axios.post('http://localhost:4200/serverport/add', serverport) .then(res => console.log(res.data)); this.setState({ name: '', port: '' }) }
Now, fill in the values and submit the form. Then, open your console panel and see the response.
Also, now check the database and see the values.
So, our data is added successfully.
Step 11: Display the server data.
Write the following code inside the IndexComponent.js file.
// IndexComponent.js import React, { Component } from 'react'; import axios from 'axios'; import TableRow from './TableRow'; export default class IndexComponent extends Component { constructor(props) { super(props); this.state = {serverports: []}; } componentDidMount(){ axios.get('http://localhost:4200/serverport') .then(response => { this.setState({ serverports: response.data }); }) .catch(function (error) { console.log(error); }) } tabRow(){ return this.state.serverports.map(function(object, i){ return <TableRow obj={object} key={i} />; }); } render() { return ( <div className="container"> <table className="table table-striped"> <thead> <tr> <td>ID</td> <td>Name</td> <td>Port</td> </tr> </thead> <tbody> {this.tabRow()} </tbody> </table> </div> ); } }
Write the stateless TableRow.js component, which we must create inside the components folder.
// TableRow.js import React, { Component } from 'react'; class TableRow extends Component { render() { return ( <tr> <td> {this.props.obj._id} </td> <td> {this.props.obj.name} </td> <td> {this.props.obj.port} </td> <td> <button className="btn btn-primary">Edit</button> </td> <td> <button className="btn btn-danger">Delete</button> </td> </tr> ); } } export default TableRow;
Step 12: Edit and update the data.
First, add the Link to the TableRow.js file.
// TableRow.js
import { Link } from 'react-router-dom';
<Link to={"/edit/"+this.props.obj._id} className="btn btn-primary">Edit</Link>
Add the following code to the EditComponent.js file.
// EditComponent.js import React, { Component } from 'react'; import axios from 'axios'; export default class EditComponent extends Component { constructor(props) { super(props); this.onChangeHostName = this.onChangeHostName.bind(this); this.onChangePort = this.onChangePort.bind(this); this.onSubmit = this.onSubmit.bind(this); this.state = {name: '', port: ''}; } componentDidMount() { axios.get('http://localhost:4200/serverport/edit/'+this.props.match.params.id) .then(response => { this.setState({ name: response.data.name, port: response.data.port }); }) .catch(function (error) { console.log(error); }) } onChangeHostName(e) { this.setState({ name: e.target.value }); } onChangePort(e) { this.setState({ port: e.target.value }); } onSubmit(e) { e.preventDefault(); const serverport = { name: this.state.name, port: this.state.port } axios.post('http://localhost:4200/serverport/update/'+this.props.match.params.id, serverport) .then(res => console.log(res.data)); this.setState({ name: '', port: '' }) this.props.history.push('/index'); } render() { return ( <div style={{marginTop: 50}}> <h3>Edit New Server</h3> <form onSubmit={this.onSubmit}> <div className="form-group"> <label>Add Host Name: </label> <input type="text" value={this.state.name} className="form-control" onChange={this.onChangeHostName}/> </div> <div className="form-group"> <label>Add Server Port: </label> <input type="text" value={this.state.port} className="form-control" onChange={this.onChangePort}/> </div> <div className="form-group"> <input type="submit" value="Update server" className="btn btn-primary"/> </div> </form> </div> ) } }
Here, you can see that our data is updated successfully. Now, the only thing remaining is deleting. So, to create a delete function inside the TableRow.js file.
// TableRow.js import React, { Component } from 'react'; import { Link } from 'react-router-dom'; import axios from 'axios'; class TableRow extends Component { constructor(props) { super(props); this.delete = this.delete.bind(this); } delete() { axios.get('http://localhost:4200/serverport/delete/'+this.props.obj._id) .then(console.log('Deleted')) .catch(err => console.log(err)) } render() { return ( <tr> <td> {this.props.obj._id} </td> <td> {this.props.obj.name} </td> <td> {this.props.obj.port} </td> <td> <Link to={"/edit/"+this.props.obj._id} className="btn btn-primary">Edit</Link> </td> <td> <button onClick={this.delete} className="btn btn-danger">Delete</button> </td> </tr> ); } } export default TableRow;
That’s it for this tutorial.
Krunal Lathiya is a seasoned Computer Science expert with over eight years in the tech industry. He boasts deep knowledge in Data Science and Machine Learning. Versed in Python, JavaScript, PHP, R, and Golang. Skilled in frameworks like Angular and React and platforms such as Node.js. His expertise spans both front-end and back-end development. His proficiency in the Python language stands as a testament to his versatility and commitment to the craft.
./src/App.js
Module not found: Can’t resolve ‘./components/CreateComponent’ in ‘C:\Users\GCUF\my\src’
i found this error
Rename the folder
C:\Users\GCUF\my\src\component
to
C:\Users\GCUF\my\src\components
There is a typo in the tutorial.
By the way, great tutorial! Thanks guys.
Thanks for drawing my attention, I have updated the components folder name.
Hi Krunal, this is a really usefull tutorial, thank you for that.
The only thing that I don’t understand is why when udating a data, I have to refresh my Index to see the new data. How can I change the props without reloading the page ?
Hi Krunal, this is very helpful tutorial.
Please give answer for the question which is asked by Ynohtna as I am also facing the same issue.
Hope for your positive response.
Hi Krunal, this is a really helpful tutorial.
Please give response for the question which Ynohtna had asked as I am also facing the same issue.This is also happening while deleting a record.
It is necessary to pass Table component callback to TableRow as shown here
https://stackoverflow.com/questions/35537229/how-to-update-parents-state-in-react
Hello Thank you a lot for this tutorial, I have a problem when I click on submit button , I get this error in console :
POST http://localhost:4200/serverport/add 404 (Not Found)
createError.js:17 Uncaught (in promise) Error: Request failed with status code 404
at createError (createError.js:17)
at settle (settle.js:19)
at XMLHttpRequest.handleLoad (xhr.js:78)
createError @ createError.js:17
settle @ settle.js:19
handleLoad @ xhr.js:78
Promise.then (async)
onSubmit @ CreateComponent.js:33
callCallback @ react-dom.development.js:147
invokeGuardedCallbackDev @ react-dom.development.js:196
invokeGuardedCallback @ react-dom.development.js:250
invokeGuardedCallbackAndCatchFirstError @ react-dom.development.js:265
executeDispatch @ react-dom.development.js:571
executeDispatchesInOrder @ react-dom.development.js:596
executeDispatchesAndRelease @ react-dom.development.js:695
executeDispatchesAndReleaseTopLevel @ react-dom.development.js:704
forEachAccumulated @ react-dom.development.js:676
runEventsInBatch @ react-dom.development.js:844
runExtractedEventsInBatch @ react-dom.development.js:852
handleTopLevel @ react-dom.development.js:5025
batchedUpdates$1 @ react-dom.development.js:19916
batchedUpdates @ react-dom.development.js:2246
dispatchEvent @ react-dom.development.js:5105
interactiveUpdates$1 @ react-dom.development.js:19978
interactiveUpdates @ react-dom.development.js:2267
dispatchInteractiveEvent @ react-dom.development.js:5081
I have the same like you normally.
Thank you a lot for your answer and help.
PS: I have a question : axios is the only way to get form data with react and node?
This tutorial was awesome! I was finally able to sign up a user and save the data in mongo.
How do I login in a user using Axios and not Passport? Can you please write a tutorial for that? Keep up the good work!