Gatsby结合WordPress使用gatsby-source-tribe-events插件时,无活动场景下allTribeEvents字段缺失的GraphQL条件查询方案问询
你遇到的这个问题很典型:当WordPress中没有发布任何活动时,gatsby-source-tribe-events插件不会在GraphQL Schema中生成allTribeEvents字段,导致你的静态查询在构建阶段直接抛出「Cannot query field "allTribeEvents" on type "Query"」的错误。下面是两种可行的解决方法,按推荐程度排序:
方法一:自定义Gatsby Schema,强制字段始终存在
这是最简单直接的方案,我们可以手动在gatsby-node.js中定义Schema,让allTribeEvents字段不管有没有数据都存在,没有活动时就返回空数组。
在项目根目录的gatsby-node.js文件中添加以下代码:
exports.createTypes = ({ actions }) => { const { createTypes } = actions; const typeDefs = ` # 先定义TribeEvent的结构,根据你实际用到的字段来写 type TribeEvent implements Node { id: ID! title: String date: String # 这里可以补充你需要的其他字段,比如活动地点、描述等 } # 定义连接类型,对应allTribeEvents的返回结构 type TribeEventsConnection { nodes: [TribeEvent] } # 强制Query类型包含allTribeEvents字段 type Query { allTribeEvents: TribeEventsConnection } `; createTypes(typeDefs); };
重启Gatsby开发服务后,不管WordPress有没有活动,allTribeEvents字段都会存在。之后你只需要在组件里检查data.allTribeEvents.nodes的长度,就能判断是否有活动数据了,原组件可以改成这样:
export default function Events() { const data = useStaticQuery(graphql` query EventsQuery { allTribeEvents { nodes { id title date # 其他你需要的字段 } } }`); const events = data.allTribeEvents.nodes; return ( <div className="events-container"> {events.length > 0 ? ( events.map(event => ( <div key={event.id} className="event-card"> <h3>{event.title}</h3> <p>活动日期:{event.date}</p> </div> )) ) : ( <p className="no-events">目前没有即将举办的活动哦~</p> )} </div> ); }
方法二:使用页面查询+条件指令(适合需要动态控制的场景)
如果你不想修改Schema,也可以用GraphQL的条件指令来控制是否查询allTribeEvents,但这个方法需要把useStaticQuery换成页面查询(因为静态查询不支持传递变量)。
首先把组件改成页面组件,或者在页面中引入这个组件,然后编写页面查询:
import { graphql } from "gatsby"; export default function Events({ data }) { // 检查是否有活动数据 const hasEvents = data.allTribeEvents?.nodes?.length > 0; return ( <div> {hasEvents ? ( data.allTribeEvents.nodes.map(event => ( <div key={event.id}> <h3>{event.title}</h3> <p>{event.date}</p> </div> )) ) : ( <p>暂无活动</p> )} </div> ); } // 页面查询,使用@include指令根据变量决定是否查询字段 export const query = graphql` query EventsQuery($shouldQueryEvents: Boolean!) { allTribeEvents @include(if: $shouldQueryEvents) { nodes { id title date } } } `;
然后在gatsby-node.js中创建页面时,先查询是否有活动,再传递对应的变量:
exports.createPages = async ({ graphql, actions }) => { const { createPage } = actions; // 先查询是否存在活动数据 const eventCheckResult = await graphql(` query { allTribeEvents { nodes { id } } } `); // 判断是否有活动 const shouldQueryEvents = eventCheckResult.data?.allTribeEvents?.nodes.length > 0; // 创建Events页面并传递变量 createPage({ path: "/events", component: require.resolve("./src/components/Events.js"), context: { shouldQueryEvents: shouldQueryEvents, }, }); };
这个方法稍显繁琐,但适合需要更精细控制查询逻辑的场景。
总结
优先推荐方法一,因为它改动最小,只需要自定义一次Schema,就能彻底解决字段不存在的问题,后续组件逻辑也能保持简洁。
内容的提问来源于stack exchange,提问作者vasilis 123

