I found an elegant soultion to our nested comments problems.
I found the Solution from StackOverflow:
[https://stackoverflow.com/a/36829986]
Originally, the comments will be inserted into the database one after another.
We will have an api GET to get all the comments by the postid and get the data in json format like this:
[
{
id: 1,
parentId: null
},
{
id: 2,
parentId: 1
},
{
id: 3,
parentId: 1
},
{
id: 4,
parentId: 3
},
{
id: 5,
parentId: 4
}]
Every comment will have a parentid. If it's a top level comment, posted from the main comment box, this will set to be null
Inside Comment.jsx
(where we are going to display all the comments)
We will store the comments in the redux store and on render,
We will load the comments and make them into nested form using a utility function:
This function takes in the raw comments, and produces a new comment array that will be in nested form.
function nestComments(commentList) {
const commentMap = {};
// move all the comments into a map of id => comment
commentList.forEach(comment => commentMap[comment.id] = comment);
// iterate over the comments again and correctly nest the children
commentList.forEach(comment => {
if(comment.parentId !== null) {
const parent = commentMap[comment.parentId];
(parent.children = parent.children || []).push(comment);
}
});
// filter the list to return a list of correctly nested comments
return commentList.filter(comment => {
return comment.parentId === null;
});
}
It will output something like this:
[
{
"id":1,
"parentId":null,
"children":[
{
"id":2,
"parentId":1
},
{
"id":3,
"parentId":1,
"children":[
{
"id":4,
"parentId":3,
"children":[
{
"id":5,
"parentId":4
}
]
}
]
}
]
}
]
We will now just store this into a variable and render the comments components like we did earlier.
This should now load up all comments in nested form.
When we submit a new comment it will go to the dispatch and push() the comment into the state.
The app will re-render, run the nestComments
function and the reply now should be shown on the page.
Since now we have a set of comments stored into the state, comments
, we will find the total number of comments,
comments.length
In React:
var commentHeader = '';
if(comments.length) {
if(comments.length > 1) {
commentHeader = `${comments.length} Comments`;
} else {
commentHeader = `1 Comment`;
}
} else {
commentHeader = 'No comments';
}
// Display the comment header:
<div>{commentHeader}</div>
If we can't fix this bug, we may disable the feature entirely.
Everytime we post a new comment or reply, it will run this function handleForm
We will put the comment to the store by calling the dispatch first.
Then we will send this comment to the backend using the fetch
api.
For this we will have to create an endpoint that supports a POST method.
The handleForm
will call the fetch
method and inside the body of this method will be the comment.
example, fetch with the POST method:
fetch('/api/comment/new', {
method: "POST",
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(comment)
})
.then(res => res.json())
.then(res => {
if(res.success) {
// Do some app logic
}
})
.catch(err => // handle error event)
You should look up how to create an endpoint in python that takes a POST request.
The request will be in plaintext. You have to convert that plaintext into JSON javascript object to find the comment details.
Store the comment into the database and send a json response back:
{success: true}
It will wait for the server. Once the server has saved this comment to the database, it will send a success message, that the app can read and continue.
By storing these info onto the state and linking them into the Comment.jsx
component.
In redux/store.js
:
defaultState = {
user: {}, // user info, store this from auth page
post: {}, // post info
comments: [],
}
Make this user info accessible inside the Comment.jsx:
function mapStateToProps(state) {
return { user: state.user, post: state.post, comments: state.comments };
}