尝试递归呈现评论 ReactJs

Trying to recursively render comments ReactJs

这是我的评论数据结构。我想我有错误的数据结构来递归地呈现评论。请指教。我可以得到一个评论和一个回复,但不是未知数量的回复。

  "comments": [
    {
      "id": 1,
      "content": "This is so great!",
      "recipe_id": 1,
      "commentable_id": 1,
      "commentable_type": "Recipe",
      "user_id": 1,
      "created_at": "2020-09-08T00:16:55.296Z",
      "updated_at": "2020-09-08T00:16:55.296Z"
    },
    {
      "id": 2,
      "content": "This is another one",
      "recipe_id": 1,
      "commentable_id": 1,
      "commentable_type": "Comment",
      "user_id": 1,
      "created_at": "2020-09-08T00:16:55.323Z",
      "updated_at": "2020-09-08T00:16:55.323Z"
    },
    {
      "id": 3,
      "content": "This is another one",
      "recipe_id": 1,
      "commentable_id": 2,
      "commentable_type": "Comment",
      "user_id": 1,
      "created_at": "2020-09-08T00:16:55.332Z",
      "updated_at": "2020-09-08T00:16:55.332Z"
    },

有两种方法可以实现:

您可以将回复存储为评论的子项:

{
  id: 3,
  content: "this is a comment",
  replies: [
    {
      id: 1,
      content: "This is a reply"
    }
]

或者您可以将回复存储在与评论相同的级别。如果您选择此方法,您将需要一个 reply_to 属性,如果它是回复,它应该引用评论 ID,如果它是直接评论而不是评论,则应该引用 null(或者最好只是取消设置)回复。

您选择哪种方法取决于您的其余数据结构和应用程序行为。

假设您从 API 获得的数据结构是固定不变的,您可以从该平面数据中“膨胀”一棵评论树。我省略了下面的 user-id 和日期信息以缩短内容。

想法是 <CommentBoxes> 将评论列表呈现为 <CommentBox> 组件;传递完整的评论列表以确保 <CommentBox> 可以过滤它以找到它正在呈现的评论的子评论(如果有的话)。

const commentData = [
  {
    id: 1,
    content: "This is so great!",
    recipe_id: 1,
    commentable_id: 1,
    commentable_type: "Recipe",
  },
  {
    id: 2,
    content: "This is another one",
    recipe_id: 1,
    commentable_id: 1,
    commentable_type: "Comment",
  },
  {
    id: 3,
    content: "This is another one",
    recipe_id: 1,
    commentable_id: 2,
    commentable_type: "Comment",
  },
];

const CommentBox = ({ comment, allComments }) => {
  const children = allComments.filter(
    (c) => c.commentable_type === "Comment" && c.commentable_id === comment.id
  );
  return (
    <li>
      {comment.content}
      {children ? <CommentBoxes comments={children} allComments={allComments} /> : null}
    </li>
  );
};

const CommentBoxes = ({ comments, allComments }) => (
  <ul>
    {comments.map((c) => (
      <CommentBox comment={c} allComments={allComments} key={c.id} />
    ))}
  </ul>
);

const App = () => {
  const rootComments = commentData.filter((c) => c.commentable_type === "Recipe");
  return <CommentBoxes comments={rootComments} allComments={commentData} />;
};

ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.1/umd/react-dom.production.min.js"></script>
<div id="root"></div>