Gatsby+Contentful技术求助:如何将文章列表展示在首页而非单独动态页面(已遇TypeError报错)
解决方案:两种方式实现首页展示Contentful文章列表
你遇到的核心问题主要有两个:一是直接导入news-list.js时,组件依赖的分页查询参数(skip/limit)没有传递导致报错;二是gatsby-node.js中创建的首页路径被src/pages/index.js覆盖,所以配置没生效。下面给你两种可行的解决思路:
方法一:直接在首页组件(index.js)中查询并渲染文章列表
这种方式最简单,不需要依赖gatsby-node.js的分页配置,直接在首页写查询获取文章数据。你当前的index.js已经有雏形,只需要修正几个小问题:
- 修正Link跳转路径:你在
gatsby-node.js中创建的文章详情页路径是/news/${node.slug},所以Link的to属性要对应这个路径,而不是直接写node.slug。 - 合并GraphQL查询:不需要同时使用页面查询(page query)和
useStaticQuery,可以把站点元数据和文章数据合并到一个查询里,代码更简洁。
修正后的index.js代码如下:
import React from 'react'; import { graphql, Link } from 'gatsby'; import Layout from '../components/layout'; import SEO from '../components/seo'; // 合并站点元数据和文章数据的查询 export const query = graphql` query { site { siteMetadata { companyname } } allContentfulPost(sort: { fields: date, order: DESC }) { edges { node { title slug date(formatString: "MMMM Do, YYYY") } } } } `; const Index = ({ data }) => { const { companyname } = data.site.siteMetadata; const posts = data.allContentfulPost.edges; return ( <Layout> <SEO title="Home" /> <section className='c-mt-10'> <div className=''> <div className='font-mono md:flex md:justify-between'> <div className='mb-5'> <a href={`mailto:hello@${companyname}.co.uk`}> hello@pfb{companyname}.co.uk </a> <br /> <br /> <tel>+44 020 3925 6054</tel> </div> <a href='https://www.google.com/maps/place/Warnford+Court,+29+Throgmorton+St,+London+EC2N+2AT/@51.5154096,-0.0890419,17z/data=!3m1!4b1!4m5!3m4!1s0x48761cacb440b98d:0x9742679143333ff!8m2!3d51.5154096!4d-0.0868479' target='_blank' rel='noreferrer'> <address className='text-right'> Warnford Court <br /> 29 Throgmorton Street <br /> London, EC2N 2AT </address> </a> </div> </div> <div> <h2>Company News</h2> <ul> {posts.map(({ node }) => ( <li key={node.slug}> <Link to={`/news/${node.slug}`}>{node.title}</Link> <span className='block text-sm text-gray-500'>{node.date}</span> </li> ))} </ul> </div> </section> </Layout> ); }; export default Index;
方法二:让首页复用news-list.js组件(保留分页功能)
如果你想保留分页逻辑,让首页作为文章列表的第一页,需要解决gatsby-node.js创建的首页被src/pages/index.js覆盖的问题:
- 删除或重命名
src/pages/index.js:Gatsby会优先使用src/pages下的文件创建路由,所以如果存在index.js,gatsby-node.js中path: '/'的页面不会生效。你可以把原index.js的内容整合到news-list.js,或者把index.js重命名为其他名称(比如home-content.js),作为组件导入到news-list.js中。 - 调整
news-list.js,添加首页的额外内容:把原首页的联系信息等内容加到news-list.js里,或者做成组件复用。 - 确保
gatsby-node.js的分页配置正确:你的分页代码已经正确设置了第一页路径为/,只要没有src/pages/index.js冲突,这个配置就会生效。
调整后的news-list.js示例(整合首页内容):
import React from 'react'; import { Link, graphql, useStaticQuery } from 'gatsby'; import Layout from '../components/layout'; import SEO from '../components/seo'; export const query = graphql` query ($skip: Int!, $limit: Int!) { allContentfulPost(sort: { fields: date, order: DESC }, limit: $limit, skip: $skip) { edges { node { title slug date(formatString: "MMMM Do, YYYY") } } } } `; const NewsList = (props) => { // 获取站点元数据 const { site } = useStaticQuery( graphql` query { site { siteMetadata { companyname } } } ` ); const { companyname } = site.siteMetadata; const posts = props.data.allContentfulPost.edges; const { currentPage, postNumPages } = props.pageContext; return ( <Layout> <SEO title={currentPage === 1 ? "Home" : `News - Page ${currentPage}`} /> {/* 原首页的联系信息 */} <section className='c-mt-10'> <div className=''> <div className='font-mono md:flex md:justify-between'> <div className='mb-5'> <a href={`mailto:hello@${companyname}.co.uk`}> hello@pfb{companyname}.co.uk </a> <br /> <br /> <tel>+44 020 3925 6054</tel> </div> <a href='https://www.google.com/maps/place/Warnford+Court,+29+Throgmorton+St,+London+EC2N+2AT/@51.5154096,-0.0890419,17z/data=!3m1!4b1!4m5!3m4!1s0x48761cacb440b98d:0x9742679143333ff!8m2!3d51.5154096!4d-0.0868479' target='_blank' rel='noreferrer'> <address className='text-right'> Warnford Court <br /> 29 Throgmorton Street <br /> London, EC2N 2AT </address> </a> </div> </div> {/* 文章列表 */} <div className='mt-8'> <h2>Company News</h2> <div className='container mx-auto prose prose-lg'> {posts.map(({ node }) => { const title = node.title || node.slug; return ( <div className='mb-2' key={node.slug}> <Link to={`/news/${node.slug}`}> <h3 className='underline font-sans mb-1'>{title}</h3> </Link> <div className='flex items-center justify-between'> <span className='font-mono text-sm'>{node.date}</span> </div> </div> ); })} </div> {/* 分页导航(如果需要) */} <div className='mt-6 flex justify-between'> {currentPage > 1 && ( <Link to={currentPage === 2 ? '/' : `/news/${currentPage - 1}`}> ← Previous Page </Link> )} {currentPage < postNumPages && ( <Link to={`/news/${currentPage + 1}`}> Next Page → </Link> )} </div> </div> </section> </Layout> ); }; export default NewsList;
之后,删除src/pages/index.js,重新启动Gatsby开发服务器,首页/就会显示带分页的文章列表,同时保留原首页的联系信息。
关键注意事项
- 路由优先级:Gatsby中
src/pages下的文件会自动生成路由,优先级高于gatsby-node.js创建的页面,所以如果要让gatsby-node创建的首页生效,必须移除src/pages/index.js。 - Link路径匹配:确保文章详情页的
Link路径和gatsby-node.js中createPage的path完全一致,否则会出现404错误。 - GraphQL查询类型:页面组件可以使用page query(
export const query),而普通组件只能使用useStaticQuery或StaticQuery,这也是你之前直接导入news-list.js报错的原因——news-list依赖page query的参数,直接导入时没有传递pageContext和data。
内容的提问来源于stack exchange,提问作者mrpbennett
相关产品推荐
相关产品推荐

