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

如何在Next.js的Sanity项目中基于Slug获取当前文章类别并过滤展示同类别相关文章?

解决Sanity同类别相关文章展示问题

你已经走对了方向,其实完全不用依赖useRouter——因为你已经通过getServerSideProps拿到了当前文章的完整数据(包括category字段),直接用这个值来过滤相关文章就好。下面给你两种可行的实现方案:

方案一:服务端预获取相关文章(推荐)

这种方式更高效,不需要客户端额外发请求,直接在服务端把当前文章和同类别文章一起获取完成:

修改你的getServerSideProps代码:

export const getServerSideProps: GetServerSideProps = async ({ params }) => {
  // 1. 获取当前文章的完整数据
  const currentPostQuery = `*[_type == "projectschema" && slug.current == $id][0] { 
    _id, title, category, date, website, thumbnail, client, company, 
    description, review, author, authorjob, image1, image2, image3, image4, image5, slug 
  }`;
  const currentProject = await sanityClient.fetch(currentPostQuery, {
    id: params?.id,
  });

  if (!currentProject) {
    return { notFound: true };
  }

  // 2. 获取同类别且排除当前文章的相关文章
  const relatedPostsQuery = `*[_type == "projectschema" && category == $category && _id != $currentId] {
    _id, title, slug, thumbnail, category
  }`;
  const relatedProjects = await sanityClient.fetch(relatedPostsQuery, {
    category: currentProject.category,
    currentId: currentProject._id,
  });

  return {
    props: {
      projects: currentProject,
      relatedProjects, // 将相关文章作为props传给组件
    },
  };
};

然后在组件中直接使用relatedProjects展示相关内容:

const SingleProject = ({ projects, relatedProjects }: any) => {
  return (
    <>
      <div className="single__page">
        <div className="down__arrow"></div>
        <div className="single__header">
          <h2>{projects.category}</h2>
          {/* 展示同类别相关文章 */}
          <div className="related-posts">
            <h3>相关文章</h3>
            {relatedProjects.length > 0 ? (
              <ul>
                {relatedProjects.map(post => (
                  <li key={post._id}>
                    <a href={`/posts/${post.slug.current}`}>{post.title}</a>
                  </li>
                ))}
              </ul>
            ) : (
              <p>暂无同类别文章</p>
            )}
          </div>
        </div>
      </div>
    </>
  );
};

方案二:客户端过滤已有数据

如果你坚持要在客户端用useState存储所有文章再过滤,也可以这样实现:

const SingleProject = ({ projects }: any) => {
  const [allPosts, setAllPosts] = useState<any[]>([]);
  // 根据当前文章类别过滤出相关文章(排除自身)
  const relatedPosts = allPosts.filter(
    post => post.category === projects.category && post._id !== projects._id
  );

  useEffect(() => {
    sanityClient
      .fetch(`*[ _type == "projectschema"] { _id, title, category, slug }`)
      .then(result => setAllPosts(result));
  }, []);

  return (
    <>
      <div className="single__page">
        <div className="down__arrow"></div>
        <div className="single__header">
          <h2>{projects.category}</h2>
          {/* 展示相关文章 */}
          <div className="related-posts">
            <h3>相关文章</h3>
            {relatedPosts.length > 0 ? (
              <ul>
                {relatedPosts.map(post => (
                  <li key={post._id}>
                    <a href={`/posts/${post.slug.current}`}>{post.title}</a>
                  </li>
                ))}
              </ul>
            ) : (
              <p>暂无同类别文章</p>
            )}
          </div>
        </div>
      </div>
    </>
  );
};

关键说明:

  • 为什么不用useRouter?因为你已经通过getServerSideProps拿到了当前文章的category值,直接用projects.category就可以,不需要再从路由解析slug重复查询数据。
  • 服务端预获取的优势:减少客户端请求次数,页面加载更快,还能避免客户端渲染时的内容闪烁问题。

内容的提问来源于stack exchange,提问作者Julia Schafer

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 00:27:45