如何在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
相关产品推荐
相关产品推荐

