Reputation: 192
👋
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.
Upvotes: 5
Views: 3215
Reputation: 80041
You're not too far off. GraphQL supports multiple discrete nodes being queried in the same query:
export const query = graphql`
{
products: allMarkdownRemark(
filter: { frontmatter: { type: { eq: "product" } } }
) {
edges {
# ...
}
}
pages: allMarkdownRemark(
filter: { frontmatter: { type: { eq: "pages" } } }
) {
edges {
# ...
}
}
}
`
Note that I've used aliases to fetch the same initial node (allMarkdownRemark
) with separate filters in the same GraphQL query. This will result in data.products
and data.pages
being passed into your default
exported React component.
To clean this up, you can use fragments, allowing you to colocate your products
query in your Carousel
file:
In carousel.js
(or whatever file houses your Carousel component):
export const query = graphql`
fragment Products on Query {
products: allMarkdownRemark(
filter: { frontmatter: { type: { eq: "product" } } }
) {
edges {
# ...
}
}
}
`
Then in your page file:
export const query = graphql`
{
pages: allMarkdownRemark(
filter: { frontmatter: { type: { eq: "pages" } } }
) {
edges {
# ...
}
}
...Products
}
`
Note: if you're using Gatsby 1.x you'll need to change the on Query
portion of the fragment to on RootQueryType
.
Assuming you're using Gatsby v2, you can also use StaticQuery instead of combining the query into one. This is particularly useful if your pages have no bearing on the Carousel of products.
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} />}
/>
);
Upvotes: 8