Skip to content

Instantly share code, notes, and snippets.

@tamalchowdhury
Created November 26, 2020 10:14
Show Gist options
  • Save tamalchowdhury/a8971b9383061a99c4c73b179cd21552 to your computer and use it in GitHub Desktop.
Save tamalchowdhury/a8971b9383061a99c4c73b179cd21552 to your computer and use it in GitHub Desktop.
Solution for nested comments in reddit clone

Nested comments implementation in reddit clone

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.

Posting a new comment or reply

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.

Displaying Number of comments

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>

+ - open collapse thread

If we can't fix this bug, we may disable the feature entirely.

How do we send the comment to the backend?

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.

How do we get the current userID, postID and other info?

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 };
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment