In my recent job switch, the interviewer asked me to implement Nested Comments and reply functionality in ReactJS. Creating an interactive comment and reply functionality for a website can significantly enhance user engagement and provide a better user experience. In this interview article, we will explore how to implement a comment system where each comment has a text input, a reply button, and the ability to show or hide replies.
Requirements
- Comment Input and Reply Button: Each comment should have a text input field and a reply button.
- Display Children Comments: Display the comment’s children under each comment and each comment shall have a text area and a Reply button as specified in Step 1
- Reply to Comments: When the reply button is clicked, the entered text should be added as a child comment.
- Show/Hide Comments: Each comment should have a button to toggle the visibility of its child comments.
Comments Data:
The interviewer shared this Link(Click Here), mentioned copying the data in the URL, and asked to fetch the data by faking a promise.
const promise = new Promise((resolve, reject) => {
resolve(data);
});
Here, the data is nothing but the data that I copied from the URL.
1. Setting Up the App
Component
First, let’s create the main App component that will fetch comment data from the promise and render the Comments
component.
import { useEffect, useState } from "react";
import "./styles.css";
import Comments from "./Comments";
const promise = new Promise((resolve, reject) => {
resolve(data)
});
export default function App() {
const [comments, setComments] = useState([]);
useEffect(() => {
promise
.then((data) => {
setComments(data);
})
.catch((error) => console.error("Error fetching:", error));
}, []);
return (
<div className="App">
<h1>Blog Comments</h1>
<Comments com={comments} setComments={setComments} />
</div>
);
}
In this App
component:
- We use the
useState
hook to manage the comments data. - The
useEffect
hook is used to fetch data from the API when the component mounts. - The fetched data is passed to the
Comments
component via props.
2. Creating the Comments
Component
The Comments
component will handle the rendering of comments and their nested replies.
// Comments.js
import React, { useState } from "react";
import Reply from "./Reply";
const Comments = (props) => {
const { com } = props;
const [showComments, setShowComments] = useState(true);
const addReplyToComment = (commentId, reply) => {
// Find the comment in the comments state and add the reply
const updatedComments = com.map((comment) => {
if (comment._id === commentId) {
return {
...comment,
children: [...comment.children, reply],
};
}
return comment;
});
// Update the comments state with the updated comments
props.setComments(updatedComments);
};
return (
<div>
{com?.length > 0 &&
com?.map((c) => {
return (
<div key={c._id}>
<div className="comment">{c.comment}</div>
<Reply commentId={c._id} addReplyToComment={addReplyToComment} />
{c?.children?.length > 0 ? (
<div className="reply">
<button onClick={() => setShowComments(!showComments)}>
{showComments ? "Hide Comments" : "Show Commnets"}
</button>
{showComments && <Comments com={c.children} />}
</div>
) : null}
</div>
);
})}
</div>
);
};
export default Comments;
In the Comments
component:
- The
showComments
state is used to toggle the visibility of nested comments. - The component maps through the comments array and renders each comment.
- If a comment has children, a button to toggle the visibility of the child comments is displayed.
3. Adding a Reply
Component
The Reply
component provides a simple input field for users to type their replies.
// Reply.js
import React, { useState } from "react";
const Reply = (props) => {
const { commentId, addReplyToComment } = props;
const [reply, setReply] = useState("");
const handleReplyChange = (e) => {
setReply(e.target.value);
};
const handleReplySubmit = () => {
// Create the reply object
const newReply = {
_id: Math.random().toString(36).substr(2, 9), // Generate a random ID
comment: reply,
children: [],
};
// Add the reply to the main comments state
addReplyToComment(commentId, newReply);
// Clear the reply input
setReply("");
};
return (
<div className="reply-container">
<input
type="text"
value={reply}
onChange={handleReplyChange}
placeholder="Reply"
/>
<button onClick={handleReplySubmit}>Submit Reply</button>
</div>
);
};
export default Reply;
We can style our components to look at least the bare minimum.
/* styles.css */
.comment {
margin-bottom: 10px;
padding: 10px;
background-color: #f0f0f0;
}
.reply-container {
margin-top: 10px;
}
.reply-container input[type="text"] {
width: 200px;
padding: 5px;
margin-right: 10px;
}
.reply-container button {
padding: 5px 10px;
background-color: #007bff;
color: #fff;
border: none;
cursor: pointer;
}
.reply-container button:hover {
background-color: #0056b3;
}
After, putting it all together, this is how the whole Component will look like.
This example demonstrates fetching data, rendering comments and replies, and handling nested structures in React. Implementing nested comments in React involves managing state, rendering recursive components, and handling asynchronous data fetching. With this foundation, you can further enhance the functionality