在Gatsby中如何构建GraphQL数据以包含MDX父目录名称
如何让Gatsby GraphQL返回按类别分组的MDX数据
Gatsby的GraphQL本身无法直接返回带动态类别键的嵌套结构(比如category1、category2这类动态字段),但可以通过提取文件类别信息+查询扁平数据+代码分组的方式实现你要的结构,具体步骤如下:
1. 从文件路径提取类别字段
首先确保gatsby-config.js已配置文件源,指向checks目录:
module.exports = { plugins: [ { resolve: `gatsby-source-filesystem`, options: { name: `checks`, path: `${__dirname}/checks/`, }, }, `gatsby-plugin-mdx`, ], }
然后在gatsby-node.js中添加onCreateNode钩子,从文件路径里提取类别(即checks下的子目录名),并把这个字段绑定到MDX节点上:
exports.onCreateNode = ({ node, getNode, actions }) => { const { createNodeField } = actions if (node.internal.type === `Mdx`) { const fileNode = getNode(node.parent) // 从相对路径中提取类别:比如checks/category1/example1.mdx,取第1级子目录名 const category = fileNode.relativeDirectory.split('/')[0] createNodeField({ node, name: `category`, value: category, }) } }
2. 查询所有MDX节点数据
在需要使用数据的页面/组件中,编写GraphQL查询获取所有checks目录下的MDX节点,包含我们新增的category字段和frontmatter信息:
query AllChecksQuery { allMdx(filter: {fields: {sourceName: {eq: "checks"}}}) { nodes { fields { category } frontmatter { title slug topic } } } }
3. 在代码中按类别分组数据
拿到查询结果后,用JavaScript的reduce方法把扁平的节点数组转换成你想要的嵌套结构:
import { graphql } from "gatsby" export default function ChecksPage({ data }) { // 按category分组,生成目标结构 const groupedChecks = data.allMdx.nodes.reduce((acc, node) => { const category = node.fields.category if (!acc[category]) { acc[category] = { nodes: [] } } acc[category].nodes.push(node) return acc }, {}) // 此时groupedChecks就是你要的结构:{category1: {nodes: [...]}, category2: {...}} return ( <div> {Object.entries(groupedChecks).map(([category, { nodes }]) => ( <section key={category}> <h2>{category}</h2> <ul> {nodes.map((item) => ( <li key={item.frontmatter.slug}> {item.frontmatter.title} </li> ))} </ul> </section> ))} </div> ) } export const query = graphql` query AllChecksQuery { allMdx(filter: {fields: {sourceName: {eq: "checks"}}}) { nodes { fields { category } frontmatter { title slug topic } } } } `
为什么GraphQL编辑器无法直接生成该结构?
GraphQL的查询结构是静态定义的,无法返回动态命名的字段(比如动态的category1、category2)。因此必须先获取扁平的节点列表,再在客户端代码中完成分组处理,这是Gatsby这类静态站点生成器的常规实现方式。
内容的提问来源于stack exchange,提问作者Jimothey
相关产品推荐
相关产品推荐

