GatsbyJS createPage模板引入自定义组件的解析报错与数据传递问题
你遇到的三类报错本质上都是同一个原因:Gatsby 对 GraphQL 查询的文件作用域有严格规则——只有通过 createPages API 注册的页面级模板组件,才能在文件顶层定义带页面动态参数(如当前页面 $id)的 pageQuery 查询。普通的嵌套自定义组件(如你的 Herotext)本身不在 Gatsby 的 GraphQL 查询解析链路里,在组件文件内单独写的关联页面 ID 的查询语句,既不会被 Gatsby 的 webpack 流程识别收集,也无法传入构建时的动态页面参数,自然就会出现:
- Gatsby 报文件解析失败,无法识别文件内的 GraphQL 内容
- eslint 解析时不认识
graphql标记,抛出第5行意外 token 的语法错误 - 组件内打印 data 为 undefined,因为 Gatsby 从来没给这类自定义组件注入查询结果
另外你之前在 GraphiQL IDE 里测试查询正常,是因为 IDE 是独立的调试环境,只要查询语法合法就能返回结果,和 Gatsby 构建时的查询收集逻辑是完全独立的两套流程。
1. 清理自定义组件内的无效代码
直接删除 Herotext 组件文件内所有的 GraphQL 查询语句,这一步就能直接解决 Gatsby 文件解析失败、eslint 报语法错的问题。
注意:如果需要让自定义组件独立做固定数据查询,可以在组件内使用 useStaticQuery Hook,但这种方式不支持传入当前页面的动态 ID 参数,完全不匹配你当前按页面ID查ACF字段的需求,不要在这个场景下用。
2. 统一在页面级模板中完成所有数据查询
把之前写在 Herotext 组件里的、需要从 wpPage 中获取的 ACF hero 字段,全部合并到 WpPage.js 的顶层 pageQuery 中,确保查询可以正确拿到动态匹配的当前页面数据:
// src/templates/page/WpPage.js import { graphql } from "gatsby" import Herotext from "../hero/herotext" // 原有查询逻辑保留,只需要把之前Herotext里要的ACF字段补充进来 export const pageQuery = graphql` query WpPageById($id: String!) { wpPage(id: {eq: $id}) { # 原有页面通用渲染需要的字段 title content # 补充hero区块需要的ACF字段 acf { heroHeading heroText } } } `
3. 通过组件传参传递数据
在 WpPage.js 的渲染逻辑中,把查询拿到的 hero 相关字段,作为 props 传给 Herotext 组件,替换原来 h1 标签的位置:
const WpPage = ({ data }) => { const currentPage = data.wpPage return ( <main> {/* 传入hero区块需要的全部数据 */} <Herotext heading={currentPage.acf?.heroHeading} content={currentPage.acf?.heroText} /> {/* 原有页面内容渲染逻辑保留 */} <div className="page-content"> <div dangerouslySetInnerHTML={{ __html: currentPage.content }} /> </div> </main> ) } export default WpPage
4. 简化自定义组件的渲染逻辑
把 Herotext 组件改成纯接收 props 的展示组件,不需要内部处理任何数据获取逻辑:
// src/templates/hero/herotext.js const Herotext = ({ heading, content }) => { return ( <section className="page-hero"> <h2>{heading}</h2> <p>{content}</p> </section> ) } export default Herotext
内容的提问来源于stack exchange,提问作者TurboTobias

