Nested comments in Reactjs
I have the following json:
{
"comments":[
{
"id":1,
"comment_text":"asdasdadasdsadsadadsa",
"author":"adsfasdasdsad",
"post_id":1,
"ancestry":null,
"archived":false,
"created_at":"2014-10-16T23:16:44.173Z",
"updated_at":"2014-10-16T23:16:44.173Z",
"is_moderated":false,
"avatar_url":null,
"slug":null,
"blog_id":2,
"children":[
]
},
{
"id":2,
"comment_text":"idlsfghlskdhvbsldfhjdslifds\nzf\ndsf\nds\nf\ns\nf\ns\nfds\nfsdjghfsdligjhsepfiguhefdliguhefldiughfeliughnfesg\nf\nsg\ns\ng\ns\ndf\nsd\nf\nsdgsofughlefidughls;uhgsuhg.vskjfhglsiuhg.sfv",
"author":"asdsdasdad",
"post_id":1,
"ancestry":null,
"archived":false,
"created_at":"2014-10-16T23:17:02.270Z",
"updated_at":"2014-10-16T23:17:02.270Z",
"is_moderated":false,
"avatar_url":null,
"slug":null,
"blog_id":2,
"children":[
{
"id":3,
"comment_text":"fdsfdsfdsfsdfsfsdf",
"author":"sdfdsfdsfdsfds",
"post_id":1,
"ancestry":"2",
"archived":false,
"created_at":"2014-11-28T17:39:47.059Z",
"updated_at":"2014-11-28T17:39:47.059Z",
"is_moderated":false,
"avatar_url":null,
"slug":null,
"blog_id":2,
"children":[
{
"id":4,
"comment_text":"fdsfdsfdsdsfdsfds",
"author":"sdfsdfdsfsdfdsfds",
"post_id":1,
"ancestry":"2/3",
"archived":false,
"created_at":"2014-11-28T17:39:53.049Z",
"updated_at":"2014-11-28T17:39:53.049Z",
"is_moderated":false,
"avatar_url":null,
"slug":null,
"blog_id":2,
"children":[
{
"id":5,
"comment_text":"sdfdsfdsfdsfdssdfsdfdsfdsfdsfds",
"author":"sdfsdfdsfdsfdsf",
"post_id":1,
"ancestry":"2/3/4",
"archived":false,
"created_at":"2014-11-28T17:40:02.032Z",
"updated_at":"2014-11-28T17:40:02.032Z",
"is_moderated":false,
"avatar_url":null,
"slug":null,
"blog_id":2,
"children":[
]
}
]
}
]
}
]
}
]
}
As you can see, some of the comments contain comments children: []
. I need to create nested comments in Reactjs based on this key.
I was able to do this in a very messy jquery way, but with React I want to move away from jquery and create a clean reactive nested comment base.
Does anyone know of any examples, ideas, or a way to do this? What I have so far:
var Comments = React.createClass({
render: function() {
<div>
<ul>
<li>sample</li>
</ul>
{this.props.children}
</div>
}
});
My idea was to loop over the comments and say that if they have children, just create another comment like
for (var i = 0; i < comments.length; i++) {
<Comments>
if (children) {
<Comments></Comments>
}
</Comments>
}
But that doesn't usually work, I can encapsulate this into a function and say:
comments: function(comments){
for (var i = 0; i < comments.length; i++) {
<Comments>
if (children) {
this.comments(comments);
}
</Comments>
}
}
Am I anywhere near on the right track?
source to share
You need two components: Comments and a comment.
Comment = React.createClass({
render: function(){
var comment = this.props.comment;
return <div>
<p>{comment.author} says {comment.comment_text}</p>
<Comments comments={comment.children} />
</div>
}
});
Comments = React.createClass({
render: function(){
return <div>
{this.props.comments.map(function(comment){
return <Comment key={comment.id} comment={comment} />
})
</div>
}
});
Comment displays comments, which in turn can display Comment nodes, etc. This builds the comment structure recursively.
source to share
It's easier to do this with just one component if you are responsible for rendering your own children:
var Comment = React.createClass({
render() {
var comment = this.props.comment
return <div>
<div dangerouslySetInnerHTML={{__html: comment.comment_text}}/>
{comment.children.length > 0 && comment.children.map((child) => {
return <Comment key={child.id} comment={child}/>
})}
</div>
}
})
If you want to do this without nesting components so that you just display a flat list <Comment>
s, you can first linearize the comment tree into a list, for example.
function flattenComments(comments, flatComments, level) {
for (var i = 0, l = comments.length; i < l; i++) {
var comment = comments[i]
flatComments.push({comment: comment, level: level})
if (comment.children.length > 0) {
flattenComments(comment.children, flatComments, level + 1)
}
}
}
var flatComments = []
flattenComments(comments, flatComments, 0)
var renderedComments = flatComments.map((props) => {
return <Comment {...props}/>
})
source to share