I am studying nested comments functionality in React JS. I have trouble deleting nested comments. Basically every comment has a property replies, which is array of objects (exactly same comment object as the parent ones).
When I try to update the parent state in the inner loop (updateCommentsData(parentStateCopy);) with copied and modified array of objects it throws me this error:
updateCommentsData is not a function even though modified array of objects seems to be correct when console logging it.
State in App component:
let [commentsData, updateCommentsData] = useState();
let [currentUser, setCurrentUser] = useState();
async function getData() {
const path = "./src/data/data.json";
try {
const req = await fetch(path);
const res = await req.json();
updateCommentsData(res.comments);
setCurrentUser(res.currentUser);
} catch (e) {
console.log("Error: " + e.message);
}
}
Delete function:
let repliesStateCopy = [];
let parentStateCopy = JSON.parse(JSON.stringify(commentsData));
function deleteComment(id) {
for (let i = 0; i < commentsData.length; i++) {
if (commentsData[i].id === id) {
updateCommentsData((prev) => {
return prev.filter((item) => item.id !== id);
});
break;
} else {
if (commentsData[i].replies.length !== 0) {
for (let j = 0; j < commentsData[i].replies.length; j++) {
repliesStateCopy.push(commentsData[i].replies[j]);
if (commentsData[i].replies[j].id === id) {
repliesStateCopy = repliesStateCopy.filter(
(item) => item.id !== id
);
parentStateCopy[i].replies = repliesStateCopy;
updateCommentsData(parentStateCopy);
break;
}
}
}
}
}
JSON Data looks like that:
{
"currentUser": {
"image": {
"png": "./images/avatars/image-juliusomo.png",
"webp": "./images/avatars/image-juliusomo.webp"
},
"username": "juliusomo"
},
"comments": [
{
"id": 1,
"content": "Impressive! Though it seems the drag feature could be improved. But overall it looks incredible. You've nailed the design and the responsiveness at various breakpoints works really well.",
"createdAt": "1 month ago",
"score": 12,
"user": {
"image": {
"png": "./images/avatars/image-amyrobson.png",
"webp": "./images/avatars/image-amyrobson.webp"
},
"username": "amyrobson"
},
"replies": []
},
{
"id": 2,
"content": "Woah, your project looks awesome! How long have you been coding for? I'm still new, but think I want to dive into React as well soon. Perhaps you can give me an insight on where I can learn React? Thanks!",
"createdAt": "2 weeks ago",
"score": 5,
"user": {
"image": {
"png": "./images/avatars/image-maxblagun.png",
"webp": "./images/avatars/image-maxblagun.webp"
},
"username": "maxblagun"
},
"replies": [
{
"id": 3,
"content": "If you're still new, I'd recommend focusing on the fundamentals of HTML, CSS, and JS before considering React. It's very tempting to jump ahead but lay a solid foundation first.",
"createdAt": "1 week ago",
"score": 4,
"replyingTo": "maxblagun",
"user": {
"image": {
"png": "./images/avatars/image-ramsesmiron.png",
"webp": "./images/avatars/image-ramsesmiron.webp"
},
"username": "ramsesmiron"
},
"replies": []
},
{
"id": 4,
"content": "I couldn't agree more with this. Everything moves so fast and it always seems like everyone knows the newest library/framework. But the fundamentals are what stay constant.",
"createdAt": "2 days ago",
"score": 2,
"replyingTo": "ramsesmiron",
"user": {
"image": {
"png": "./images/avatars/image-juliusomo.png",
"webp": "./images/avatars/image-juliusomo.webp"
},
"username": "juliusomo"
},
"replies": []
}
]
},
2
Answers
Found the solution. The problem was that I was creating 2 separate states for parent comments and for replies and rendered them individually. Like this:
Comments List component
And then inside CommentsCard Component I would have this state:
and render it like this:
Then when I tried to update the replies state it actually updated just not rendered on the screen. This delete function now does the job:
and this is how I render the comments and replies in CommentsList component now:
I think problem is updateCommentsData is being called directly with parentStateCopy rather than using the state setter function’s callback pattern (prev => newState).
Try this code :