首页 > 解决方案 > How to use GraphQL queries in a container class component

问题描述

My current GatsbyJS project is a one pager with a carousel and some other content.

Background

The carousel should be filled with information about some products. My goal is to let the carousel build itself by iterating through all markdown files, picking the ones with these three lines at the top of the file:

---
type: product
---

So I've created a CarouselContainer (class component) and a Carousel component (functional component). The Container should load the markdown via GraphQL query and pass the resulting products object to it's nested component. Then the component should map over the object and create the carousel.

But there are also other markdown files for menu lists, text modals and so on. They have the type: page. I thought preparing a few GraphQL queries would be the solution. But it turned out to be more difficult than expected...

The container component is a class component, so I am not able to call the query directly in it (https://github.com/gatsbyjs/gatsby/issues/3991#issuecomment-364939030).

Then I thought putting multiple queries into the pages/index.js could be the solution.

export const indexQuery = graphql`
query IndexQuery {
  allMarkdownRemark(filter: {frontmatter: {type: {eq: "page"}}}) {
    edges {
      node {
        frontmatter {
          title
          text
        }
      }
    }
  }
}
`

export const productsQuery = graphql`
query ProductsQuery {
  allMarkdownRemark(filter: {frontmatter: {type: {eq: "product"}}}) {
    edges {
      node {
        id
        frontmatter {
          title
          content
        }
      }
    }
  }
}
`

Nope again. Using GraphQL fragments should be a solution...

Q Can someone tell me how to prepare fragments for that purpose and/or have another idea how to get the markdown content right into my container?

Thanks for reading.

标签: javascriptreactjsgraphqlgatsby

解决方案


你离得并不远。GraphQL 支持在同一个查询中查询多个离散节点:

export const query = graphql`
  {
    products: allMarkdownRemark(
      filter: { frontmatter: { type: { eq: "product" } } }
    ) {
      edges {
        # ...
      }
    }

    pages: allMarkdownRemark(
      filter: { frontmatter: { type: { eq: "pages" } } }
    ) {
      edges {
        # ...
      }
    }
  }
`

请注意,我使用别名allMarkdownRemark在同一个 GraphQL 查询中使用不同的过滤器来获取相同的初始节点 ( )。这将导致data.products并被data.pages传递到您default导出的 React 组件中。

要清理它,您可以使用片段,允许您将products查询放在Carousel文件中:

carousel.js(或任何包含 Carousel 组件的文件)中:

export const query = graphql`
  fragment Products on Query {
    products: allMarkdownRemark(
      filter: { frontmatter: { type: { eq: "product" } } }
    ) {
      edges {
        # ...
      }
    }
  }
`

然后在您的页面文件中:

export const query = graphql`
  {
    pages: allMarkdownRemark(
      filter: { frontmatter: { type: { eq: "pages" } } }
    ) {
      edges {
        # ...
      }
    }

    ...Products
  }
`

注意:如果您使用的是 Gatsby 1.x,您需要将on Query片段的部分更改为on RootQueryType.

假设您使用的是 Gatsby v2,您还可以使用StaticQuery而不是将查询合并为一个。如果您的页面与产品的轮播无关,这将特别有用。

import React from "react";
import { graphql, StaticQuery } from "gatsby";

class Carousel extends React.Component {
  // ...
}

export default props => (
  <StaticQuery
    query={graphql`
      products: allMarkdownRemark(
        filter: { frontmatter: { type: { eq: "product" } } }
      ) {
        edges {
          # ...
        }
      }
    `}
    render={({ products }) => <Carousel products={products} {...props} />}
  />
);

推荐阅读