Lecture Notes Of Day 29: MongoDB with React.js

Rashmi Mishra
0

Lecture Notes Of Day 29
MongoDB with React.js

Objective: Use MongoDB as a backend for a React.js frontend.
Outcome: Students will be able to create a full-stack web application using MongoDB, Express.js, and React.js.


1. Introduction to Full-Stack Development

A full-stack web application includes both the frontend (user interface) and the backend (server, database). In this lesson, we are going to create a full-stack application using MongoDB, Express.js, and React.js, commonly known as the MERN stack.

  • Frontend: React.js will be used to create the user interface.
  • Backend: Express.js will serve as the backend framework to handle HTTP requests.
  • Database: MongoDB will store and manage the data for our application.

2. Setting Up the Project

To get started, let's set up both the frontend and backend of the application.

2.1 Setting Up the Backend (Express.js and MongoDB) 

1.   Install Node.js: Make sure you have Node.js installed on your computer. You can download it from Node.js official website.

2.   Create a New Directory: Create a folder for your project and navigate to it in your terminal.

mkdir mern-stack-app

cd mern-stack-app

3.   Initialize npm: Initialize a new Node.js project by running the following command.

npm init -y

4.   Install Required Packages: Install Express, Mongoose (MongoDB ODM), and Cors (to handle cross-origin requests) using the following command.

npm install express mongoose cors

5.   Create Backend Files: Inside your project folder, create the following files:

o    server.js: This will set up the Express server and connect to MongoDB.

o    models/User.js: This will define the schema for storing user data in MongoDB.

o    routes/userRoutes.js: This will define routes for the user operations (CRUD).

6.   Connecting to MongoDB: In the server.js file, set up the connection to MongoDB.

const express = require('express');

const mongoose = require('mongoose');

const cors = require('cors');

const app = express();

app.use(cors());

app.use(express.json()); // to parse JSON data

mongoose.connect('mongodb://localhost:27017/mern-stack', { useNewUrlParser: true, useUnifiedTopology: true })

  .then(() => console.log('Connected to MongoDB'))

  .catch(err => console.log('Failed to connect to MongoDB', err));

const PORT = process.env.PORT || 5000;

app.listen(PORT, () => {

  console.log(`Server running on port ${PORT}`);

});

7.   Creating a User Model: Define the User schema in models/User.js.

const mongoose = require('mongoose');

const userSchema = new mongoose.Schema({

  name: { type: String, required: true },

  email: { type: String, required: true, unique: true },

  password: { type: String, required: true }

});

module.exports = mongoose.model('User', userSchema);

8.   Setting Up Routes: In routes/userRoutes.js, create routes for creating and fetching users.

const express = require('express');

const router = express.Router();

const User = require('../models/User');

// POST route for creating a new user

router.post('/users', async (req, res) => {

  const { name, email, password } = req.body;

  const newUser = new User({ name, email, password });

  try {

    await newUser.save();

    res.status(201).json(newUser);

  } catch (error) {

    res.status(400).json({ message: error.message });

  }

});

 

// GET route for fetching all users

router.get('/users', async (req, res) => {

  try {

    const users = await User.find();

    res.json(users);

  } catch (error) {

    res.status(400).json({ message: error.message });

  }

}); 

module.exports = router;

9.   Mounting Routes: Finally, in server.js, import and mount the routes.

const userRoutes = require('./routes/userRoutes');

app.use('/api', userRoutes);

2.2 Setting Up the Frontend (React.js)

1.   Create React App: In the root directory of your project, create a new React app using the following command.

npx create-react-app client

cd client

2.   Install Axios: Install Axios for making HTTP requests from React to the backend.

npm install axios

3.   Create a User Component: Inside the src folder of the React app, create a new file called User.js to handle user-related actions like displaying users and adding new ones.

Example of displaying users in User.js:

import React, { useEffect, useState } from 'react';

import axios from 'axios';

const User = () => {

  const [users, setUsers] = useState([]);

  useEffect(() => {

    axios.get('http://localhost:5000/api/users')

      .then(response => {

        setUsers(response.data);

      })

      .catch(error => {

        console.error('There was an error fetching the users!', error);

      });

  }, []);

  return (

    <div>

      <h1>User List</h1>

      <ul>

        {users.map(user => (

          <li key={user._id}>{user.name} - {user.email}</li>

        ))}

      </ul>

    </div>

  );

};

export default User;

4.   Running the Backend and Frontend:

o    Start the backend by running:

node server.js

o    Start the frontend by navigating to the client folder and running:

npm start

5.   Now, you should be able to access your React app on http://localhost:3000 and interact with the data coming from MongoDB via Express.js.


3. Testing the Application

1.   Test Backend: Use Postman or your browser to test the backend:

o    Create a user: POST http://localhost:5000/api/users with JSON body:

{

  "name": "John Doe",

  "email": "john.doe@example.com",

  "password": "password123"

}

o    Fetch all users: GET http://localhost:5000/api/users.

2.   Test Frontend: Ensure the user list is displayed on the React application. Any new user added through the backend should appear in the frontend.


4. Conclusion

By the end of this lesson, students will have a working full-stack web application that connects a React.js frontend with a MongoDB backend via Express.js. Students should be able to:

  • Set up a MongoDB database.
  • Create and use models with Mongoose in the backend.
  • Send and receive data between the frontend (React.js) and backend (Express.js) using Axios.
  • Handle basic CRUD operations in a full-stack application.

5. Homework/Practice

1.   Add the ability to delete users from the list on both the backend and frontend.

2.   Implement user authentication (login/signup) and store the user's session using cookies or JWT.

3.   Create a form to add new users from the React frontend and connect it to the backend.

SOLUTION:

1. Delete Users from the List (Backend and Frontend)

1.1 Backend - Add a Route to Delete Users

In the backend (routes/userRoutes.js), add a new route to handle the deletion of a user by their ID.

// DELETE route for deleting a user by ID

router.delete('/users/:id', async (req, res) => {

  try {

    const deletedUser = await User.findByIdAndDelete(req.params.id);

    if (!deletedUser) {

      return res.status(404).json({ message: 'User not found' });

    }

    res.status(200).json({ message: 'User deleted successfully' });

  } catch (error) {

    res.status(400).json({ message: error.message });

  }

});

1.2 Frontend - Add a Delete Button and Handle Deletion

In User.js (frontend), add a button to delete users. Modify the component to send a DELETE request to the backend.

import React, { useEffect, useState } from 'react';

import axios from 'axios'; 

const User = () => {

  const [users, setUsers] = useState([]);

   useEffect(() => {

    axios.get('http://localhost:5000/api/users')

      .then(response => {

        setUsers(response.data);

      })

      .catch(error => {

        console.error('There was an error fetching the users!', error);

      });

  }, []);

   const deleteUser = async (userId) => {

    try {

      await axios.delete(`http://localhost:5000/api/users/${userId}`);

      setUsers(users.filter(user => user._id !== userId));

    } catch (error) {

      console.error('There was an error deleting the user!', error);

    }

  };

   return (

    <div>

      <h1>User List</h1>

      <ul>

        {users.map(user => (

          <li key={user._id}>

            {user.name} - {user.email}

            <button onClick={() => deleteUser(user._id)}>Delete</button>

          </li>

        ))}

      </ul>

    </div>

  );

};

export default User;

Now, when you click the "Delete" button, the user will be deleted from both the frontend and the backend.


2. User Authentication (Login/Signup) with JWT

2.1 Backend - User Authentication (JWT Setup)

Install jsonwebtoken and bcryptjs to handle user authentication:

npm install jsonwebtoken bcryptjs

2.2 Create JWT Authentication Logic

In server.js, add the following code for generating JWT tokens upon user login:

const bcrypt = require('bcryptjs');

const jwt = require('jsonwebtoken');

const User = require('./models/User');

// POST route for user signup

router.post('/signup', async (req, res) => {

  const { name, email, password } = req.body;

  const hashedPassword = await bcrypt.hash(password, 10);

  const newUser = new User({ name, email, password: hashedPassword });

  try {

    await newUser.save();

    res.status(201).json({ message: 'User created successfully' });

  } catch (error) {

    res.status(400).json({ message: error.message });

  }

});

 // POST route for user login

router.post('/login', async (req, res) => {

  const { email, password } = req.body;

  const user = await User.findOne({ email });

   if (!user) {

    return res.status(400).json({ message: 'Invalid credentials' });

  }

   const isMatch = await bcrypt.compare(password, user.password);

  if (!isMatch) {

    return res.status(400).json({ message: 'Invalid credentials' });

  }

   const token = jwt.sign({ userId: user._id }, 'your_jwt_secret', { expiresIn: '1h' });

  res.json({ token });

});

2.3 Frontend - Implement Signup and Login Forms

Create two forms: one for signing up and one for logging in.

Signup Form (Signup.js):

import React, { useState } from 'react';

import axios from 'axios';

const Signup = () => {

  const [name, setName] = useState('');

  const [email, setEmail] = useState('');

  const [password, setPassword] = useState('');

   const handleSubmit = async (e) => {

    e.preventDefault();

    const user = { name, email, password };

     try {

      await axios.post('http://localhost:5000/api/signup', user);

      alert('Signup successful!');

    } catch (error) {

      console.error('There was an error signing up!', error);

    }

  };

   return (

    <form onSubmit={handleSubmit}>

      <input type="text" value={name} onChange={(e) => setName(e.target.value)} placeholder="Name" required />

      <input type="email" value={email} onChange={(e) => setEmail(e.target.value)} placeholder="Email" required />

      <input type="password" value={password} onChange={(e) => setPassword(e.target.value)} placeholder="Password" required />

      <button type="submit">Sign Up</button>

    </form>

  );

};

 export default Signup;

Login Form (Login.js):

import React, { useState } from 'react';

import axios from 'axios';

const Login = () => {

  const [email, setEmail] = useState('');

  const [password, setPassword] = useState('');

  const [token, setToken] = useState(null);

  const handleSubmit = async (e) => {

    e.preventDefault();

    const user = { email, password };

    try {

      const response = await axios.post('http://localhost:5000/api/login', user);

      setToken(response.data.token);

      alert('Login successful!');

    } catch (error) {

      console.error('There was an error logging in!', error);

    }

  };

  return (

    <form onSubmit={handleSubmit}>

      <input type="email" value={email} onChange={(e) => setEmail(e.target.value)} placeholder="Email" required />

      <input type="password" value={password} onChange={(e) => setPassword(e.target.value)} placeholder="Password" required />

      <button type="submit">Login</button>

    </form>

  );

};

export default Login;

Once logged in, you can store the JWT in the browser's localStorage or cookies for subsequent requests to secure routes.


3. Create a Form to Add New Users from React Frontend

Create a form to submit new users to the backend.

import React, { useState } from 'react';

import axios from 'axios';

 const AddUser = () => {

  const [name, setName] = useState('');

  const [email, setEmail] = useState('');

  const [password, setPassword] = useState('');

   const handleSubmit = async (e) => {

    e.preventDefault();

    const newUser = { name, email, password };

     try {

      await axios.post('http://localhost:5000/api/users', newUser);

      alert('User added successfully!');

    } catch (error) {

      console.error('There was an error adding the user!', error);

    }

  };

   return (

    <form onSubmit={handleSubmit}>

      <input type="text" value={name} onChange={(e) => setName(e.target.value)} placeholder="Name" required />

      <input type="email" value={email} onChange={(e) => setEmail(e.target.value)} placeholder="Email" required />

      <input type="password" value={password} onChange={(e) => setPassword(e.target.value)} placeholder="Password" required />

      <button type="submit">Add User</button>

    </form>

  );

};

 export default AddUser;


Conclusion

With the solutions above, you:

  • Added functionality to delete users both in the frontend and backend.
  • Implemented user authentication (signup and login) using JWT for securing routes.
  • Created a form to add new users from the React frontend to the MongoDB backend.


Tags

Post a Comment

0Comments

Post a Comment (0)

About Me