Hi,
it is possible to use GraphQL in every component? I've read the tutorial about GraphQL in gatsby (https://www.gatsbyjs.org/tutorial/part-four/), there is explained how to use GraphQL in an layout/page file.
But for example: i've a page called "home" and one page "about". On each page there is an sidebar with an list of recent blog-posts. I would build an component "RecentBlogPosts", but i would avoid to query the blog posts in every page and pass it to the component. Instead it would be nice to query the blog posts in the "RecentBlogPosts" component.
I've tried to export an query in the component, but it didn't work (see snippet below).
import React from 'react';
const RecentBlogPosts = (props) => {
console.log('props', props);
return (
<div>
<h1>Blog-Posts</h1>
</div>
);
};
export const query = graphql`
query Items {
site {
siteMetadata {
title
description
keywords
}
}
}
`;
export default RecentBlogPosts;
Many thanks!
you can query in layouts
Ok. In components it is not possible?
You can but you need to compose the fragments into the top level query. I'm on a phone so I can't type out an example but check out the relay modern docs for composition (we use their compiler) as well as the gatsby doc site source code which uses this pattern
@jquense Any chance you have time to elaborate now?
I looked through various pieces of Gatsby components with GraphQL queries that are not pages and I don't see how the example here or my own code is any different. Something is just not clicking on my end.
@dlindahl Have you looked at the usage of fragments by several of the example sites?
I just took a look at ReasonML's site, specifically the GuideSidebar. It looks like the pattern is to define the desired query as a _fragment_ which is then referenced by the root node:
// in src/components/MyComponent.js
const MyComponent = () => <div/>
export default MyComponent
export const myQuery = graphql`
fragment posts on RootQueryType {
allFile {
edges {
node {
relativePath
prettySize
extension
birthTime(fromNow: true)
}
}
}
}
`
// in src/pages/index.js
const Homepage = ({ data }) => <div/>
export default Homepage
export const query = graphql`
query HomepageQuery {
...posts
}
`
While I sort of understand how that is working, it is not quite the same as supporting GraphQL on any component. To elaborate, I'm trying to do something like:
// in src/provider/PostsProvider.js
const PostsProvider = ({ children, data }) => {
const posts = data.allMarkdownRemark.edges.map((edge) => edge.node)
return children(posts)
}
export default PostsProvider
export const query = graphql`
query PostsQuery {
allMarkdownRemark {
totalCount
edges {
node {
id
frontmatter {
title
date
}
excerpt
}
}
}
}
`
// in src/pages/index.js
import PostsProvider from '../providers/PostsProvider'
const Homepage = (props) => (
<div>
<PostsProvider>
{(posts) => posts.map(({ title })=> (
<div>{title}</div>
))}
</PostsProvider>
</div>
)
Is such a pattern not supported here? If not, is that due to how Gatsby is meant to be used or is it something specific to GraphQL?
It's specific to Gatsby. Gatsby needs to know when to load data. It does that by tying data to pages (and layouts) so it can know if a user is visiting page x, it needs to load the data associated with page x.
This is why pages are the "root" of the GraphQL queries.
Relay does something similar except the "roots" are arbitrary.
Apollo is more freeform (as I understand it — I haven't used it) and uses a system-wide runtime aggregation to combine requests.
I've just stumbled across this as i'm trying to create a navigation component that is referenced in the layout and i can't get this to work. Wondering about how fragment works. Is there any examples?
I thought this was weird in the beginning, but got to like fragments more and more, feels like having more control of what loads what
but am always open to new approaches and ways ;)
Closing this as there's no action to be taken.
Most helpful comment
It's specific to Gatsby. Gatsby needs to know when to load data. It does that by tying data to pages (and layouts) so it can know if a user is visiting page x, it needs to load the data associated with page x.
This is why pages are the "root" of the GraphQL queries.
Relay does something similar except the "roots" are arbitrary.
Apollo is more freeform (as I understand it — I haven't used it) and uses a system-wide runtime aggregation to combine requests.