在 React 中渲染嵌套/线程注释

IT技术 javascript recursion reactjs
2021-05-19 14:01:48

鉴于以下数组,我想comments通过使用parentId.

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

我认为使用下面的组件我可以通过评论递归,但输出不是我所期望的(它似乎<ul>为每个评论呈现一个新元素。)我有点新的react和javascript,所以也许我没有正确实现递归,或者应该comments采用不同的结构?

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>
);
2个回答

如果您将该列表转换为实际反映注释嵌套层次结构的结构,那么您将可以更轻松地构建用于呈现它们的组件。

[
  {
    id: 1,
    children: [
      { id: 2, children: [] },
      { id: 3, children: [ ... ] }
    ]
  }
]

您可以实现一个函数来进行转换。

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

这里有一个关于如何从平面结构转到嵌套注释列表的想法。一旦你完成了这个实现,你所需要的只是一个递归的 React 组件。

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

如果你需要一个需要深入未知水平的例子,我用这个解决了

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
}