Fixing Duplicate Error & Adding Comments in Our CloudNoteBook App 📝🐞
While testing our CloudNoteBook app, you may have noticed a tricky bug — clicking
Add Note quickly (or submitting the same note twice) creates duplicate notes
with the same key, which React doesn't like at all. In this tutorial, we'll squash
that bug for good, and then reward ourselves by adding a brand-new Comments feature so
users can leave notes-on-notes right inside CloudNoteBook.
In this React JS tutorial for beginners, we will learn:
Why duplicate notes and duplicate key warnings happen in React
Generating truly unique IDs using uuid
Preventing duplicate note submissions with a guard check
Adding a comments array to each note's data structure
Writing an addComment method to update nested state safely
Rendering a comment box and comment list inside each note card
---
Why Do Duplicate Notes Happen?
This bug usually shows up in one of two ways: either the user double-clicks the
Add Note button before the state updates, or notes are being keyed using
index instead of a stable, unique id. When two notes end up with
the same key, React can't tell them apart while re-rendering, which leads
to duplicate entries, mismatched updates, and console warnings like
"Warning: Encountered two children with the same key."
---
Step 1: Give Every Note a Truly Unique ID
Let's install the uuid package so every note gets a guaranteed-unique identifier,
instead of relying on array index or timestamps that can collide.
import { v4 as uuidv4 } from "uuid";
---
Step 2: Add a Guard Check Before Adding a Note
Open Notes.js and update the addNote method so it checks whether an
identical, not-yet-saved note is already being submitted, and ignores the click if so.
This stops accidental double-submits from creating duplicates.
addNote = (title, description, tag) => {
// Guard: ignore duplicate rapid submissions of the same note
const isDuplicate = this.state.notes.some(
(note) =>
note.title.trim().toLowerCase() === title.trim().toLowerCase() &&
note.description.trim().toLowerCase() === description.trim().toLowerCase()
);
if (isDuplicate) {
console.warn("Duplicate note detected — submission ignored.");
return;
}
const newNote = {
id: uuidv4(),
title,
description,
tag,
comments: [],
};
this.setState({ notes: [...this.state.notes, newNote] });
};
---
Step 3: Use note.id as the key, Not the Index
Wherever we render the list of notes, make sure the key prop uses
note.id instead of the array index. This alone fixes most "duplicate key" console
warnings.
{notes.map((note) => (
<Noteitem key={note.id} note={note} />
))}
---
Step 4: Add a comments Array to Every Note
To support comments, every note object now carries its own comments array
(as shown in addNote above). Each comment will be a small object with its own
unique id and text.
// Example note shape after this update
{
id: "a1b2c3",
title: "Grocery List",
description: "Milk, eggs, bread",
tag: "Personal",
comments: [
{ id: "c1", text: "Don't forget oat milk!" }
]
}
---
Step 5: Write the addComment Method
This method finds the correct note by id and appends a new comment to its
comments array — without mutating state directly.
addComment = (noteId, commentText) => {
if (!commentText.trim()) return;
const updatedNotes = this.state.notes.map((note) => {
if (note.id === noteId) {
return {
...note,
comments: [...note.comments, { id: uuidv4(), text: commentText }],
};
}
return note;
});
this.setState({ notes: updatedNotes });
};
---
Step 6: Render Comments Inside Noteitem.js
Now let's add a small comment box and comment list inside each note card. This uses local
component state to hold the text being typed before it's submitted.
import React, { useState, useContext } from "react";
import NoteContext from "../../context/notes/NoteContext";
const Noteitem = (props) => {
const context = useContext(NoteContext);
const { addComment } = context;
const { note } = props;
const [commentText, setCommentText] = useState("");
const handleAddComment = () => {
addComment(note.id, commentText);
setCommentText("");
};
return (
<div className="col-md-4 my-3">
<div className="card">
<div className="card-body">
<h5 className="card-title">{note.title}</h5>
<p className="card-text">{note.description}</p>
{/* Comments Section */}
<div className="mt-3">
<h6>Comments ({note.comments.length})</h6>
<ul className="list-group mb-2">
{note.comments.map((comment) => (
<li key={comment.id} className="list-group-item py-1">
{comment.text}
</li>
))}
</ul>
<div className="input-group">
<input
type="text"
className="form-control"
placeholder="Add a comment..."
value={commentText}
onChange={(e) => setCommentText(e.target.value)}
/>
<button className="btn btn-outline-warning" onClick={handleAddComment}>
Post
</button>
</div>
</div>
</div>
</div>
</div>
);
};
export default Noteitem;
---
Bug Cause vs Fix — Quick Reference
| Problem |
Root Cause |
Fix Applied |
| Duplicate notes on fast clicks |
No check for identical, recently-submitted note data |
Guard check inside addNote before adding to state |
| "Two children with same key" warning |
Using array index as the React key |
Switched to a stable note.id generated with uuid |
| Comments not persisting per note |
No comments field on the note object |
Added comments: [] to every note and an addComment updater |
---
Features and Learnings:-
Identified why duplicate notes and duplicate-key warnings occur in React apps.
Used the uuid package to generate stable, collision-free note IDs.
Added a guard check in addNote to block accidental duplicate submissions.
Replaced index-based keys with note.id across the notes list.
Extended the note data model with a comments array.
Wrote an immutable addComment updater using map() and spread syntax.
Built a comment input and comment list UI inside each Noteitem card.
Prepared CloudNoteBook for the next step: persisting comments to the backend/database.