(Gatsby) 在 MDX 组件中显示 frontmatter 数据

问题描述 投票:0回答:2

我正在尝试创建一个简单的

Byline
组件,在我的 MDX 帖子中使用,该组件使用
href="mailto:[email protected]"
time
标签显示网站作者,并在其 frontmatter 中给出帖子的日期。

我尝试按照 this Gatsby 教程 学习如何在组件中通过 GraphQL 查询 frontmatter。

我不太了解 React 或 GraphQL,但我知道第一个 (

author
) 是通过
site.siteMetadata.author.name
查询的(我认为?)。

至于第二个,因为它使用了帖子的frontmatter,所以我认为我应该使用

mdx.frontmatter.date

我没有让这些发挥作用。我收到这些错误:

无法读取未定义的属性(读取“站点”)

无法读取未定义的属性(读取“mdx”)

我也收到此错误:

There was an error in your GraphQL query:

Variable "$id" is not defined by operation "BylineQuery".

GraphQL request:10:19
 9 |     }
10 |     mdx(id: { eq: $id }) {
   |                   ^
11 |       frontmatter {

GraphQL request:2:3
1 |
2 |   query BylineQuery {
  |   ^
3 |     site {

这是完整的组件:

import * as React from 'react'
import { graphql } from 'gatsby'

const Byline = ({data }) => {
  return (
    <div className="byline">
      <address>Av <a href="mailto:[email protected]" rel="author">{data.site.siteMetadata.author.name}</a></address>
      <time dateTime={data.mdx.frontmatter.computerDate}>{data.mdx.frontmatter.humanDate}</time>
    </div>
  )
}

export const query = graphql`
  query BylineQuery {
    site {
      siteMetadata {
        author {
          name
        }
      }
    }
    mdx(id: { eq: $id }) {
      frontmatter {
        computerDate: date(formatString: "YYYY-MM-DD")
        humanDate: date(formatString: "D. MMMM YYYY", locale: "nb")
      }
    }
  }
`

export default Byline

gatsby-node.js

const path = require(`path`)
const { createFilePath } = require(`gatsby-source-filesystem`)

exports.createPages = async ({ graphql, actions, reporter }) => {
  const { createPage } = actions

  // Define a template for blog post
  const blogPost = path.resolve(`./src/templates/blog-post.js`)

  // Get all markdown blog posts sorted by date
  const result = await graphql(
    `
      {
        allMdx(
          sort: { fields: [frontmatter___date], order: ASC }
          limit: 1000
        ) {
          nodes {
            id
            fields {
              slug
            }
          }
        }
      }
    `
  )

  if (result.errors) {
    reporter.panicOnBuild(
      `There was an error loading your blog posts`,
      result.errors
    )
    return
  }

  const posts = result.data.allMdx.nodes

  // Create blog posts pages
  // But only if there's at least one markdown file found at "content/blog" (defined in gatsby-config.js)
  // `context` is available in the template as a prop and as a variable in GraphQL

  if (posts.length > 0) {
    posts.forEach((post, index) => {
      const previousPostId = index === 0 ? null : posts[index - 1].id
      const nextPostId = index === posts.length - 1 ? null : posts[index + 1].id

      createPage({
        path: post.fields.slug,
        component: blogPost,
        context: {
          id: post.id,
          previousPostId,
          nextPostId,
        },
      })
    })
  }
}

exports.onCreateNode = ({ node, actions, getNode }) => {
  const { createNodeField } = actions

  if (node.internal.type === `Mdx`) {
    const value = createFilePath({ node, getNode })

    createNodeField({
      name: `slug`,
      node,
      value,
    })
  }
}

exports.createSchemaCustomization = ({ actions }) => {
  const { createTypes } = actions

 
  createTypes(`
    type SiteSiteMetadata {
      author: Author
      siteUrl: String
      social: Social
    }

    type Author {
      name: String
      summary: String
    }

    type Social {
      twitter: String
      instagram: String
      mail: String
    }

    type MarkdownRemark implements Node {
      frontmatter: Frontmatter
      fields: Fields
    }

    type Frontmatter {
      title: String
      description: String
      date: Date @dateformat
    }

    type Fields {
      slug: String
    }
  `)
}

Byline.js

(目前只是测试。)

(位于

components
目录中。)

import React from "react"
import { graphql } from "gatsby"

export default function Byline({ data: { mdx } }) {
  return (
    <div>
      <h1>{mdx.frontmatter.title}</h1>
    </div>
  )
}

export const pageQuery = graphql`
  query BylineQuery($id: String) {
    mdx(id: { eq: $id }) {
      id
      body
      frontmatter {
        title
      }
    }
  }
`

gatsby-config.js

module.exports = {
  siteMetadata: {
    title: `Magnus Kolstad`,
    author: {
      name: `Magnus Rengård Kolstad`,
      summary: `Summary`,
      description: "Artikler skrevet av Magnus Kolstad",
    },
    description: `Description`,
    siteUrl: `https://kolstadmagnus.no/`,
    social: {
      mail: `[email protected]`,
      instagram: `kolstadmagnus`,
      twitter: `KolstadMagnus`,
      youtube: `UC7QpsGiWwVc9lmnIJvA9OLA`
    },
  },
  plugins: [
    `gatsby-plugin-image`,
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: `blog`,
        path: `${__dirname}/content/blog`,
      },
    },
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: `images`,
        path: `${__dirname}/src/images`,
      },
    },
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: `pages`,
        path: `${__dirname}/src/pages/`,
      }
    },
    {
      resolve: `gatsby-plugin-mdx`,
      options: {
        defaultLayouts: {
          default: require.resolve(`./src/components/layout.js`),
        },
        gatsbyRemarkPlugins: [
          {
            resolve: `gatsby-remark-images`,
            options: {
              maxWidth: `900000000000`,
              linkImagesToOriginal: false,
              backgroundColor: `none`,
            },
          },
          {
            resolve: `gatsby-remark-responsive-iframe`,
            options: {
              wrapperStyle: `margin-bottom: 1.0725rem`,
            },
          },
          `gatsby-remark-prismjs`,
          `gatsby-remark-copy-linked-files`,
          `gatsby-remark-smartypants`,
        ],
        extensions: [`.md`, `.mdx`],
      },
    },
    `gatsby-transformer-sharp`,
    `gatsby-plugin-sharp`,
    {
      resolve: `gatsby-plugin-manifest`,
      options: {
        name: `Gatsby Starter Blog`,
        short_name: `GatsbyJS`,
        start_url: `/`,
        background_color: `#ffffff`,
        display: `minimal-ui`,
        icon: `src/images/gatsby-icon.png`,
      },
    },
    `gatsby-plugin-react-helmet`,
  ],
}
reactjs graphql gatsby
2个回答
0
投票

扩展哈桑的答案

首先,这里写了一个页面查询。页面查询仅适用于 页。确保您的组件位于页面目录中。

这部分是正确的。页面查询也可以在模板中使用,这意味着它们也是页面,但它们不位于

src/pages
文件夹中,而是位于
src/templates
中(假设指南的项目结构)。

尽管查询看起来应该是这样的:

export const query = graphql`
  query BylineQuery($id: String) {
    site {
      siteMetadata {
        author {
          name
        }
      }
    }
    mdx(id: { eq: $id }) {
      frontmatter {
        computerDate: date(formatString: "YYYY-MM-DD")
        humanDate: date(formatString: "D. MMMM YYYY", locale: "nb")
      }
    }
  }

如果需要,请在 GraphiQL 游乐场 (

localhost:8000/___graphql
) 中使用硬编码
id
检查它,或者将过滤器更改为另一个方便的字段。

事实是,关键部分是您需要使用上下文将

id
gatsby-node.js
传递到模板,正如在 tutorial 中推断的那样。例如::

posts.forEach(({ node }, index) => {
  createPage({
    path: node.fields.slug,
    component: path.resolve(`./src/templates/blog-post.js`),
    // values in the context object are passed in as variables to page queries
    context: {
      title: node.title,
      id: node.id
    },
  })
})

title
id
变量将在
blog-post.js
模板中公开(在
./src/templates
下),并可用于使用这些值过滤您的帖子(在本例中)。

简化,

gatsby-node.js
创建模板页面(帖子等)并查询每个帖子的特定数据,您需要使用通过上下文发送的提升上下文变量来过滤数据。


-1
投票

首先,这里写了一个页面查询。页面查询仅适用于页面。确保您的组件位于页面目录中。该错误来自您的查询,您使用了动态参数“$id”,但没有传递变量。

export const query = graphql`
  query BylineQuery($id: String) {
    site {
      siteMetadata {
        author {
          name
        }
      }
    }
    mdx(id: { eq: $id }) {
      frontmatter {
        computerDate: date(formatString: "YYYY-MM-DD")
        humanDate: date(formatString: "D. MMMM YYYY", locale: "nb")
      }
    }
  }
`

你的查询应该是这样的。检查文档(https://www.gatsbyjs.com/docs/how-to/querying-data/page-query/

© www.soinside.com 2019 - 2024. All rights reserved.