Up until now, most of the example Gatsby pages that we’ve seen have co-located data queries and data rendering in the same file to make it easier to connect the dots between a data query and the renderer that handles the response data. Many developers prefer to formalize a separation of concerns that distinguishes between components of code that are responsible for querying data and others that perform rendering.
In Gatsby themes, separating data queries into independent components distinct from those handling rendering is often preferable to the co-location common in Gatsby pages. This is due to the fact that Gatsby themes often provide code components that are intended to be shadowed (i.e., overridden).
Without a clean separation between data query code and rendering code, a theme user would need to understand both how to issue page queries and how to perform JSX rendering. When those components are separated into distinct files, it becomes much easier for theme consumers to override individual JSX components (e.g., BlogPostList
or UserCard
) without having to rewrite the page query or StaticQuery
providing the data.
If you need to separate out page queries so they can be overridden, you can use a typical Gatsby template file to perform the necessary data collection and then provide that data to a separate component—here, a JSX component known as <BlogPostList />
(src/components/blog-post-list.js):
// example/src/templates/blog-post-list.js
import
React
from
"react"
import
{
graphql
}
from
"gatsby"
import
PostList
from
"../components/blog-post-list"
export
default
function
MyPostsList
(
props
)
{
return
<
BlogPostList
posts
=
{
props
.
allMdx
.
edges
}
/>
}
export
const
query
=
graphql
`
query {
allMdx(
sort: {
order: DESC,
fields: [frontmatter___date]
}
filter: {
frontmatter: {
draft: {
ne: true
}
}
}
) {
edges {
node {
id
frontmatter {
title
path
date(formatString: "MMMM DD, YYYY")
}
}
}
}
}
`
If you need to separate out static queries from a non-page component so they can be overridden, you can use the layout component to pass the response data from the data query to smaller rendering components as React props. In the following example, our layout component issues a static query to fetch site metadata, which is then used to populate smaller components within the layout:
// example/src/components/layout.js
import
React
from
"react"
import
{
useStaticQuery
,
graphql
}
from
"gatsby"
import
Header
from
"../header.js"
const
Layout
=
({
children
})
=>
{
const
{
site
:
{
siteMetadata
},
}
=
useStaticQuery
(
graphql
`
query
{
site
{
siteMetadata
{
title
}
}
}
`
)
const
{
title
}
=
siteMetadata
return
(
<>
<
Header
title
=
{
title
}
/>
<
main
>{
children
}</
main
>
</>
)
}
export
default
Layout
Whether you perform data querying from the standpoint of a page component (with typical page queries) or a non-page component (with static queries), it’s important to allow theme users who wish to override functionality to shadow either the data querying or the rendering mechanism rather than struggling with a component that does both. This is one way that themes differ from normal page queries: they are intended to be readable by other developers, not just ourselves or our immediate developer teams.
Leave a Reply