Gatsby is an open-source framework primarily based on React that helps construct web sites and apps. It means that you can construct your web site and apps utilizing React after which generates HTML, CSS, and JS while you construct for manufacturing.
One of many many benefits of utilizing Gatsby is that it permits accessing information by a question language known as GraphQL. GraphQL is a question language for APIs that gives an entire and comprehensible description of the information in your API, provides shoppers the ability to ask for precisely what they want and nothing extra. Gatsby makes use of GraphQL as a result of it gives the next:
- Specificity: Request solely the information wanted and never no matter is returned by the API.
- Static Construct: Carry out information transformations at construct time inside GraphQL queries.
- Standardized: It is a performant information querying language for the customarily complicated/nested information dependencies.
If you’re , you’ll be able to learn extra about why Gatsby makes use of GraphQL. On this article, I will share some helpful ideas for when utilizing GraphQL in a Gatsby undertaking.
Create Gatsby Pages from GraphQL Question
By default, pages/routes in Gatsby are created by creating a brand new file within the src/pages
folder i.e creating an about.js
file means making a web page at /about
. Nonetheless there’s one other methodology to creating pages, and that is utilizing the createPage motion along with the createPages API to programmatically create pages. This methodology additionally gives you with extra choices when creating these pages equivalent to customizing the web page’s slug.
const path = require('path')
exports.createPages = ({ graphql, actions }) => {
const { createPage } = actions
const ShopPage = path.resolve(`src/parts/shop-page.js`)
createPage({
path: "/retailer",
element: ShopPage,
context: {},
})
}
Within the code snippet above, the createPage motion is used to create a web page at
/retailer
. The createPage motion accepts a number of arguments however I will give attention to the next arguments:
path
– That is the relative URL of the web page and will at all times begin with a slash.element
– That is the trail to the React element which is used as template for this web page.context
– That is an object that may include any information to be handed right down to the React element as props.
Basically createPage helps us in every single place the place we have to create pages dynamically. A extra sensible use for the createPage motion could be creating a number of pages for every article in a publication web site. It is the perfect methodology for this use case as a result of it permits creating a number of pages programmatically from an exterior supply. It is also a very good choice as a result of we may use the information gotten from the exterior supply to create permalinks/paths for the pages. Let’s check out an instance:
const path = require('path')
exports.createPages = ({ graphql, actions }) => {
const { createPage } = actions
const ArticlePage = path.resolve(`src/parts/article-page.js`)
return new Promise((resolve, reject) => {
resolve(
graphql(
`{
articles: allArticles {
edges {
node {
id
slug
title
class {
slug
}
}
}
}
}`,
).then(end result => {
end result.information.articles.edges.forEach(edge => {
createPage({
path: `${edge.node.class.slug}/${edge.node.slug}`,
element: ArticlePage,
context: {
slug: edge.node.slug
},
})
})
}),
)
}
Within the code above, we’re querying a (fictional) exterior GraphQL supply to fetch article entries. The question physique comprises the properties that we would need to be returned within the end result which might be helpful in setting up the permalink.
The end result gotten again from the question is then used to create the pages by looping by the end result and utilizing the article’s property to create a path for the web page.
One other helpful tip for when creating pages programmatically is extracting the createPage actions simply in case they’re lots for the
gatsby-node.js
file. It helps to declutter the file and make the code extra readable.This often occurs when there are a number of queries and a number of pages to be created. See the code snippet beneath for example:
const path = require('path')
exports.createPages = ({ graphql, actions }) => {
const { createPage } = actions
const ArticlePage = path.resolve(`src/parts/article-page.js`)
const AuthorPage = path.resolve(`src/parts/author-page.js`)
const ProductPage = path.resolve(`src/parts/product-page.js`)
return new Promise((resolve, reject) => {
resolve(
graphql(
`{
articles: allArticles {
edges {
node {
id
slug
title
class {
slug
}
}
}
}
authors: allAuthors {
edges {
node {
id
slug
identify
bio
}
}
}
merchandise: allProducts {
edges {
node {
id
slug
title
}
}
}
}`,
).then(end result => {
end result.information.articles.edges.forEach(edge => {
createPage({
path: `${edge.node.class.slug}/${edge.node.slug}`,
element: ArticlePage,
context: {
slug: edge.node.slug
},
})
})
end result.information.authors.edges.forEach(edge => {
createPage({
path: `${edge.node.slug}`,
element: AuthorPage,
context: {
slug: edge.node.slug
},
})
})
end result.information.merchandise.edges.forEach(edge => {
createPage({
path: `${edge.node.slug}`,
element: ProductPage,
context: {
slug: edge.node.slug
},
})
})
}),
)
}
The code snippet above is just like the primary one we created, with the addition of extra queries to fetch extra information. If we proceed including queries and
createPage
actions at this fee, thegatsby-node.js
would grow to be cluttered and a really lengthy file to scroll by.A doable repair could be to extract the
createPage
actions to particular person information for every of the pages that you just’d wish to create within the Gatsby undertaking. This implies creating page-specific helpers to handle every web page, fairly than placing all pages in the identical place. The tip end result needs to be that the file is fairly declarative for every Gatsby hook that it implements:const path = require('path')
module.exports = (createPage, edge) => {
const ArticlePage = path.resolve(`src/parts/article-page.js`)
createPage({
path: `${edge.node.class.slug}/${edge.node.slug}`,
element: ArticlePage,
context: {
slug: edge.node.slug
},
})
}
const path = require('path')
module.exports = (createPage, edge) => {
const AuthorPage = path.resolve(`src/parts/author-page.js`)
createPage({
path: `${edge.node.class.slug}/${edge.node.slug}`,
element: AuthorPage,
context: {
slug: edge.node.slug
},
})
}
const path = require('path')
module.exports = (createPage, edge) => {
const ProductPage = path.resolve(`src/parts/product-page.js`)
createPage({
path: `${edge.node.class.slug}/${edge.node.slug}`,
element: ProductPage,
context: {
slug: edge.node.slug
},
})
}
The three code snippets above are page-specific helper features;
createArticlePages
,createAuthorPages
, andcreateProductPages
which can assist to create the article pages, writer pages, and product pages respectively. Additionally they settle for an argument of thecreatePage
motion itself and anedge
object that comprises the information wanted for creating the trail.The brand new helper features can then be used within the
gatsby-node.js
file like this.import createArticlePages from './createArticlePages'
import createAuthorPages from './createAuthorPages'
import createProductPages from './createProductPages'
exports.createPages = ({ graphql, actions }) => {
const { createPage } = actions
return new Promise((resolve, reject) => {
resolve(
graphql(
`{
articles: allArticles {
edges {
node {
id
slug
title
class {
slug
}
}
}
}
authors: allAuthors {
edges {
node {
id
slug
identify
bio
}
}
}
merchandise: allProducts {
edges {
node {
id
slug
title
}
}
}
}`,
).then(end result => {
end result.information.articles.edges.forEach(edge => {
createArticlePages(createPage, edge)
})
end result.information.authors.edges.forEach(edge => {
createAuthorPages(createPage, edge)
})
end result.information.merchandise.edges.forEach(edge => {
createProductPages(createPage, edge)
})
}),
)
}
This implementation helps to guarantee that the
gatsby-node.js
file stays decluttered and straightforward to learn.Web page question vs StaticQuery
Gatsby gives you with two strategies for fetching information utilizing GraphQL – Web page Question and StaticQuery. Web page question is a technique that means that you can use the
graphql
tag in your React parts to fetch information. The StaticQuery is a technique in which you’ll be able to the useStaticQuery React Hook to carry out queries in your React element:import { graphql } from 'gatsby'
import React from 'react'
const ArticlePage = ({ information }) => {
return (
{information.edges.map(article, index) => (
<h2>{article.title}</h2>
<p>{article.snippet}</p>
)}
)
}
export default ArticlePage
export const question = graphql`
question Articles($locale: String!) {
articles: allArticles(
filter: { locale: { eq: $locale } }
) {
edges {
node {
id
title
snippet
locale
publishDate
}
}
}
}
`
import { graphql, useStaticQuery } from 'gatsby'
import React from 'react'
const ArticlePage = ({ information }) => {
const information = useStaticQuery(graphql`
question Articles {
edges {
node {
id
title
snippet
locale
publishDate
}
}
}
`)
return (
{information.edges.map(article, index) => (
<h2>{article.title}</h2>
<p>{article.snippet}</p>
)}
)
}
export default ArticlePage
The primary distinction between each strategies is that web page queries have entry to the web page context, which is outlined in the course of the
createPage
and this basically signifies that web page queries can settle for GraphQL variables. Static queries shouldn’t have this function.One other distinction between them is that static queries can be utilized anyplace in any element however web page queries can solely be used on pages that are used as
element
property within the createPage operate.Utilizing GraphQL fragments in Gatsby
When utilizing GraphQL in Gatsby, it is almost certainly you will be in a state of affairs the place you have used a specific question a few instances throughout a number of parts. Fortunately there is a function in GraphQL known as fragments that assist you to create a set of fields after which embody them in queries the place they’d be used.
Fragments additionally assist to transform complicated queries into a lot smaller and modular queries. In a approach it is just like exporting a operate from a helper file after which reusing that operate in a number of parts:
export const question = graphql`
fragment AuthorInfo on AuthorEntry {
id
identify
slug
locale
}
`
The code snippet above is an instance of a fraction file in a Gatsby undertaking. The question above fetches particulars about an writer and we’re assuming that this question has been written a few instances all through the codebase.
Fragments will be created in any GraphQL question however I discover it higher to create the question individually in a brand new file. There are 3 key components in a fraction; the fragment’s identify, the GraphQL sort it is going to be used on and the precise physique of the question.
Utilizing the instance above,
AuthorInfo
is the identify of the fragment and what will probably be used to reference it in different parts.AuthorEntry
is the GraphQL sort and the physique is the thing values.After getting this file created, all it’s essential to do is use the fragment anyplace within the Gatsby undertaking:
import { graphql } from 'gatsby'
import React from 'react'
const ArticlePage = ({information}) => {
}
export const question = graphql`
question FetchArticle {
article {
id
slug
title
publishDate
writer {
...AuthorInfo
}
}
}
`
There is no must import the file or fragment earlier than utilizing it as a result of Gatsby already is aware of to preprocess all GraphQL queries while compiling the location.
GraphQL Fragments in Gatsby with TypeScript
In case you use TypeScript in your Gatsby undertaking, you can too outline varieties when creating your GraphQL fragment. Which means wherever you’ll use your fragment, you need to use its sort to make sure that you are getting what’s anticipated. Utilizing the code snippet beneath for example:
import { graphql } from 'gatsby'
export interface AuthorInfoFragment {
id: string
identify: string
slug: string
twitter: string
locale: string
}
export const question = graphql`
fragment AuthorInfo on AuthorEntry {
id
identify
slug
locale
}
`
Within the code snippet above, there is a GraphQL fragment known as
AuthorInfo
and an interface known asAuthorInfoFragment
, each of that are exported. These two can then be utilized in one other element to question GraphQL and examine for sort security respectively. Utilizing the code snippet beneath for example, we try to fetch an article entry utilizing the GraphQL question on the backside.import { graphql } from 'gatsby'
import React from 'react'
import { AuthorInfoFragment } from 'AuthorInfo.fragment.ts'
interface Props {
information: {
article: {
id: string
slug: string
title: string
publishDate: string
writer: AuthorInfoFragment
}
}
}
const ArticlePage = ({information}) => {
}
export const question = graphql`
question FetchArticle {
article {
id
slug
title
publishDate
writer {
...AuthorInfo
}
}
}
`
Included within the question is the
writer
property which makes use of theAuthorInfo
fragment, and we’re additionally type-checking the content material ofwriter
within theProp
TypeScript interface.GraphQL Playground for Gatsby
Everytime you run your Gatsby web site in improvement mode, it additionally launches GraphiQL, an in-browser IDE, to discover your web site’s information and schema at
localhost:8000/___graphql
:
Nonetheless, there’s an alternative choice to GraphiQL, and that is the GraphQL Playground by Prisma. It means that you can work together with all the information, schemas added by extra Gatsby plugins. GraphQL Playground makes use of parts of GraphiQL beneath the hood however is actually a extra highly effective GraphQL IDE that permits higher improvement workflows. The GraphQL Playground additionally provides extra options like:
- Interactive, multi-column schema documentation.
- A number of Tabs identical to you’d have in an IDE.
- Customizable HTTP headers.
- Question historical past.
To make use of the GraphQL Playground in your Gatsby undertaking, edit the develop
script within the package deal.json
file:
"develop": "GATSBY_GRAPHQL_IDE=playground gatsby develop",
In case you’re on Home windows then the script ought to seem like this and likewise set up the
cross-env
package deal:"develop": "cross-env GATSBY_GRAPHQL_IDE=playground gatsby develop"
As soon as you have modified the script, you’ll be able to then run
yarn develop
to run the location in improvement mode and likewise launch the brand new GraphQL Playground.
These are a number of the issues I’ve learnt while working with Gatsby and GraphQL and you may learn extra about each applied sciences right here. If in case you have any helpful Gatsby + GraphQL ideas, please share them beneath within the feedback!