Hi everyone, welcome back to the note-taking series. In Chapter 1, we focused on implementing Firebase authentication in our note-taking app to handle user sign-in and registration. In case you missed it, here’s the link to chapter 1: https://snehafarkya.hashnode.dev/firebase-authentication-in-react-chapter-1-of-note-taking-series
Now, it's time to move on to an essential part of any full-stack application: connecting a backend database. In this chapter, we’ll integrate MongoDB with our application to store and manage notes.
Why MongoDB?
MongoDB is a popular NoSQL database that stores data in a flexible, JSON-like format. Its document-based structure allows for scalability, and it's ideal for applications where the structure of data can change frequently, such as a note-taking app where the content varies between users.
Setting Up MongoDB Locally
To get started, you'll need to install MongoDB locally. You can download it from MongoDB's official website. Once installed, start MongoDB using the following command:
mongod
This will start a local MongoDB server. By default, MongoDB listens on port 27017
.
Express Server Setup
We need a backend server to interact with our MongoDB database. For this, we'll use Express and Mongoose. Here's a step-by-step guide to setting up the server:
Step 1: Initialize the Project
Create a new directory for the server, and run the following commands:
mkdir noteapp-server
cd noteapp-server
npm init -y
Install the necessary dependencies:
npm install express mongoose cors
Step 2: Building the Express Server
Now, let’s set up our basic Express server, which will handle API requests to create, retrieve, update, and delete notes in the MongoDB database.
const express = require('express');
const mongoose = require('mongoose');
const cors = require('cors');
const app = express();
app.use(cors());
app.use(express.json());
// Connect to MongoDB
mongoose.connect('mongodb://localhost:27017/<yourAppName>')
.then(() => console.log('MongoDB connected'))
.catch(err => console.error('MongoDB connection error:', err));
// Note Schema
const noteSchema = new mongoose.Schema({
title: String,
content: String,
});
const Note = mongoose.model('Note', noteSchema);
// Fetch all notes
app.get('/notes', async (req, res) => {
const notes = await Note.find();
res.json(notes);
});
// Create a new note
app.post('/notes', async (req, res) => {
const newNote = new Note({
title: req.body.title,
content: req.body.content,
});
await newNote.save();
res.json(newNote);
});
// Update a note
app.put('/notes/:id', async (req, res) => {
const updatedNote = await Note.findByIdAndUpdate(req.params.id, req.body, { new: true });
res.json(updatedNote);
});
// Delete a note
app.delete('/notes/:id', async (req, res) => {
await Note.findByIdAndDelete(req.params.id);
res.json({ message: 'Note deleted' });
});
// Start the server
const PORT = process.env.PORT || 5000;
app.listen(PORT, () => console.log(`Server running on port ${PORT}`));
Step 3: Run the Server
To start the server, run:
node index.js
This will run the server on http://localhost:5000
. At this point, you should be able to use tools like Postman or cURL to interact with your API.
Connecting the Backend to React
Now that we have our backend server running and connected to MongoDB, let’s wire it up with our React app.
Step 4: Fetch Notes in React
First, we'll update the frontend to fetch and display notes. Make sure your React app is running, and in your notes component, fetch the data from the backend:
import React, { useState, useEffect } from 'react';
import axios from 'axios';
function NoteList() {
const [notes, setNotes] = useState([]);
const [title, setTitle] = useState('');
const [content, setContent] = useState('');
const [showNotes, setShowNotes] = useState(false); // State to toggle note visibility
useEffect(() => {
axios.get('http://localhost:5000/notes')
.then(response => setNotes(response.data));
}, []);
const handleAddNote = () => {
axios.post('http://localhost:5000/notes', { title, content })
.then(response => {
setNotes([...notes, response.data]);
setTitle('');
setContent('');
});
};
const handleDeleteNote = (id) => {
axios.delete(`http://localhost:5000/notes/${id}`)
.then(() => setNotes(notes.filter(note => note._id !== id)));
};
const toggleShowNotes = () => {
setShowNotes(!showNotes); // Toggle the visibility of notes
};
return (
<div className='flex flex-col gap-4 md:w-[400px]'>
<h1>Note-Taking App</h1>
<input
type="text"
value={title}
onChange={(e) => setTitle(e.target.value)}
placeholder="Title"
className='p-4 text-base font-medium text-black focus:outline-none rounded-sm'
/>
<textarea
value={content}
onChange={(e) => setContent(e.target.value)}
placeholder="Jot down your thoughts"
className='p-4 text-base font-medium text-black focus:outline-none rounded-sm'
rows={6}
/>
<div className="flex gap-4 justify-center">
<button
onClick={handleAddNote}
className='bg-white text-black px-4 py-2 rounded-sm hover:bg-gray-300 text-base font-medium w-fit'>
Add Note
</button>
<button
onClick={toggleShowNotes}
className='bg-white text-black px-4 py-2 rounded-sm hover:bg-gray-300 text-base font-medium w-fit'>
{showNotes ? 'Hide' : 'Show'} Notes
</button>
</div>
{showNotes && (
<table className="min-w-full border-collapse bg-white shadow-md rounded-lg overflow-hidden mt-4">
<thead className="bg-gray-200">
<tr>
<th className="text-left px-6 py-4 text-xl font-semibold text-gray-700 border-b">Title</th>
<th className="text-left px-6 py-4 text-xl font-semibold text-gray-700 border-b">Content</th>
<th className="text-left px-6 py-4 text-xl font-semibold text-gray-700 border-b">Action</th>
</tr>
</thead>
<tbody>
{notes.map(note => (
<tr key={note._id} className="hover:bg-gray-100">
<td className="px-6 py-4 text-base border-b text-gray-700 border-gray-200">{note.title}</td>
<td className="px-6 py-4 text-base border-b text-gray-700 border-gray-200" style={{ maxWidth: '200px' }}>
<div className="line-clamp-2 overflow-hidden text-ellipsis">
{note.content}
</div>
</td>
<td className="px-6 py-4 text-base border-b border-gray-200">
<button
className="text-red-700 font-medium hover:text-white px-4 py-2 rounded-sm hover:bg-red-500 transition duration-200 ease-in-out"
onClick={() => handleDeleteNote(note._id)}
>
Delete
</button>
</td>
</tr>
))}
</tbody>
</table>
)}
</div>
);
}
export default NoteList;
Here, we use axios to make a GET request to our backend and store the notes in state using the useState
and useEffect
hooks.
Step 5: Add New Notes
To allow users to create new notes, we’ll add a form in our React app:
import React, { useState } from 'react';
import axios from 'axios';
const AddNote = () => {
const [title, setTitle] = useState('');
const [content, setContent] = useState('');
const handleSubmit = async (e) => {
e.preventDefault();
await axios.post('http://localhost:5000/notes', { title, content });
setTitle('');
setContent('');
};
return (
<form onSubmit={handleSubmit}>
<input
type="text"
placeholder="Note Title"
value={title}
onChange={(e) => setTitle(e.target.value)}
/>
<textarea
placeholder="Note Content"
value={content}
onChange={(e) => setContent(e.target.value)}
></textarea>
<button type="submit">Add Note</button>
</form>
);
};
export default AddNote;
This form allows users to submit new notes sent to the backend API via a POST request.
Take a sneak peek of how this is going to look: https://youtu.be/Kv39ZseSARM?si=BHE1bIHC1R3KasSa
Conclusion
In this chapter, we covered how to connect our backend to MongoDB using Mongoose, create an Express server to handle CRUD operations, and finally, integrate the backend with our React frontend to fetch and add notes.
By the end of this chapter, you should have a fully functional backend connected to MongoDB, allowing users to add, view, and delete notes.
Feel free to explore more and if this made you learn something, do post it on socials😃
Find me on this socials. I would love to connect with you:
Have a wonderful day🌻!
Stay tuned!