You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在React中调用API获取并展示指定ID的树形结构全量评论

解决方案

你当前使用的搜索接口返回的children字段仅为评论ID集合,不包含完整的评论内容,想要获取指定ID对应的全量树形评论,需要请求单item详情接口https://hn.algolia.com/api/v1/items/[故事ID],该接口返回的children字段才是嵌套的完整评论结构。

完整实现代码

import { useState, useEffect } from 'react';

// 递归渲染树形评论的组件
const CommentTree = ({ comments }) => {
  return (
    <div style={{ marginLeft: '20px', marginTop: '10px' }}>
      {comments.map(comment => (
        <div key={comment.id} className="comment-item">
          {/* 跳过已删除的评论 */}
          {comment.text && (
            <>
              <div className="comment-author" style={{ color: '#666', fontSize: '14px' }}>
                {comment.author} · {comment.points || 0} 点
              </div>
              <div 
                className="comment-content" 
                style={{ margin: '5px 0', fontSize: '14px' }}
                dangerouslySetInnerHTML={{ __html: comment.text }} 
              />
              {/* 递归渲染子评论 */}
              {comment.children?.length > 0 && <CommentTree comments={comment.children} />}
            </>
          )}
        </div>
      ))}
    </div>
  )
}

function News() {
  const [stories, setStories] = useState([]);
  // 存储当前展开评论的故事ID、对应评论数据、加载状态
  const [activeStoryId, setActiveStoryId] = useState(null);
  const [storyComments, setStoryComments] = useState([]);
  const [loadingComments, setLoadingComments] = useState(false);

  useEffect(() => {
    const getStoriesData = async () => {
      await fetch("https://hn.algolia.com/api/v1/search_by_date?tags=(story,poll)")
      .then((response) => response.json())
      .then((data) => {
        // 新增存储故事的objectID,用于后续请求评论详情
        const stories = data.hits.map(({objectID, title,url,points,children}) => ({
          id: objectID,
          title,
          url,
          points,
          commentCount: children.length // 原children是评论ID列表,仅用来算数量
        }))
        setStories(stories);
      });
    }
    getStoriesData();
  }, []);

  // 点击评论数触发获取评论详情的逻辑
  const loadComments = async (storyId) => {
    // 点击已展开的评论则收起
    if (activeStoryId === storyId) {
      setActiveStoryId(null);
      setStoryComments([]);
      return;
    }
    setLoadingComments(true);
    setActiveStoryId(storyId);
    try {
      const res = await fetch(`https://hn.algolia.com/api/v1/items/${storyId}`);
      const data = await res.json();
      setStoryComments(data.children || []);
    } catch (err) {
      console.error('评论加载失败', err);
      setStoryComments([]);
    } finally {
      setLoadingComments(false);
    }
  }

  return(
    <div className="news">
      <table className = "table">
        <thead>
          <tr><th>Title</th> <th>Points</th> <th>Comments</th></tr>
        </thead>
        <tbody>
          {stories.map((story) => (            
            <tr key={story.id}>
              <td><a className="title" href={story.url}>{story.title}</a></td>
              <td><div className="points">{story.points}</div></td>
              <td>
                <div 
                  className="comments" 
                  onClick={() => loadComments(story.id)}
                  style={{ cursor: 'pointer', color: '#007bff' }}
                >
                  {story.commentCount}
                </div>
                {/* 当前行是选中的故事,渲染评论区 */}
                {activeStoryId === story.id && (
                  <tr>
                    <td colSpan={3}>
                      {loadingComments ? <p>评论加载中...</p> : <CommentTree comments={storyComments} />}
                    </td>
                  </tr>
                )}
              </td>
            </tr>               
          ))}
        </tbody>
      </table>
    </div>
  )
}

export default News;

关键逻辑说明

  • 递归评论组件:通过CommentTree组件递归渲染嵌套的评论结构,自动适配任意层级的评论树,无需手动处理层级逻辑。
  • 懒加载评论:仅在用户点击对应故事的评论数时才请求评论详情,避免初始加载时大量并发请求拖慢性能。
  • 适配接口规则:返回的评论内容是HTML格式,所以使用dangerouslySetInnerHTML渲染,已删除评论没有text字段,渲染时做了过滤处理。

内容的提问来源于stack exchange,提问作者YASH KUMAR

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 17:24:00