Rendering nested/threaded comments in React

别来无恙 提交于 2020-12-28 21:10:23

问题


Given the below array, I'd like to render comments in a threaded manner by making use of parentId.

comments: [
    {
      id: 1,
      parentId: null
    },
    {
      id: 2,
      parentId: 1
    },
    {
      id: 3,
      parentId: 1
    },
    {
      id: 4,
      parentId: 3
    },
    {
      id: 5,
      parentId: 4
    }
  ]

I thought with the below components I'd be able to recurse through the comments, but the output is not what I'd expect (it seems to be rendering a new <ul> element for every comment.) I'm a bit new to react and javascript, so maybe I'm not implementing the recursion correctly, or should comments be structured differently?

const Comment = (props) => (
  <li>
    {props.comment.id}
    {props.comment.children.length > 0 ?
      <Comments comments={props.comment.children}/>
      : null }
  </li>
);

const Comments = (props) => (
  <ul>
    {props.comments.map((comment) => {
      comment.children = _.filter(props.comments, {'parentId': comment.id});
      return <Comment key={comment.id} comment={comment}/>
    })}
  </ul>
);

回答1:


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>
  );
}



回答2:


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
}


来源:https://stackoverflow.com/questions/36829778/rendering-nested-threaded-comments-in-react

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!