Given the below array, I\'d like to render comments
in a threaded manner by making use of parentId
.
comments: [
{
id: 1,
in case you need an example that needs to go unknown levels deep i solved with this
function Comment({text, author}){
return <div>{author}: {text}</div>
}
CommentTree(comments) {
let items = comments.map((comment) => {
return (
<div className="border-l pl-6">
<Comment
key={comment.id}
text={comment.text}
author={comment.author}
/>
{comment.children && CommentTree(comment.children)}
</div>
)
})
return items
}
If you turn that list into a structure which actually reflects the nested hierarchy of the comments, then you'll have an easier time building a component for rendering them.
[
{
id: 1,
children: [
{ id: 2, children: [] },
{ id: 3, children: [ ... ] }
]
}
]
You could implement a function to do the conversion.
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;
});
}
Here's an idea for how you could go from that flat structure to a list of nested comments. Once you're done with that implementation, all you'd need would be a recursive React component.
function Comment({ comment }) {
const nestedComments = (comment.children || []).map(comment => {
return <Comment comment={comment} />;
});
return (
<div key={comment.id}>
<span>{comment.text}</span>
<a href={comment.author.url}>{comment.author.name}</a>
{nestedComments}
</div>
);
}