Introduction
Linking your next and previous article doesn't require any packages to be installed, infact it's quite simple to implement.
If you have an up and running blog with articles then you must have used Gatsby's createPages
api. This api provides a createPage
function that takes an object as it's first argument, gatsby refers to this object as page
object. This page object takes following key's.
-
path
: a path url where your articles will be available to read from. -
component
: a path to the react component that'll render the content of the article usually referred to as article template. -
context
: an object using which you can pass any key-value that you would want to read from the article template.
We'll be using the context
key to implement this functionality.
Let's code
Each article rendered using article template get's a list of props from the createPage
function. It contains a prop named pageContext
. Any key-value, we define inside the context
will be available through this pageContext prop. We'll be passing two keys named: prev
and next
representing details of previous and next article respectively.
Getting details of next/previous articles
In order to get list of all articles, we use a GraphQL query. Something like -
const result = await graphql(`
query {
// if you're using just markdown, replace allMdx with allMarkdownRemark
allMdx(sort: { order: DESC, fields: [frontmatter___date] }) {
edges {
node {
fields {
slug
}
frontmatter {
title
}
}
}
}
}
`)
This essentially returns all the articles, in the query above, the field edges
represent list of all the articles and the field node
represent each article. Let's assign the edges
to a variable.
const articles = result.data.allMdx.edges
Now to get the next and previous article we can just use articles[index-1].node
for previous article and articles[index+1].node
for next article. And incase if it's the first article, previous would be null
and for the last article next
would be null
.
For previous article
articles.forEach(({ node }, index) => {
createPage({
...
context: {
...
prev: index === 0 ? null : articles[index - 1].node
}
})
})
For next article
articles.forEach(({ node }, index) => {
createPage({
...
context: {
...
next: index === articles.length - 1 ? null : articles[index + 1].node
}
})
})
Now we have access to the details of previous and next articles inside article template to render links for them.
Using the pageContext
In our article template, we can destructure the props to get the pageContext
like
const Article = ({ pageContext }) => {}
Let's extract details of prev/next and save them into variables.
For previous article
const prev = pageContext.prev
? {
url: `/blog/${pageContext.prev.fields.slug}`,
title: pageContext.prev.frontmatter.title
}
: null
For next article
const next = pageContext.next
? {
url: `/blog/${pageContext.next.fields.slug}`,
title: pageContext.next.frontmatter.title
}
: null
Now render them on your article using jsx
.
<div>
{prev && (
<Link to={prev.url}>
<span>Previous</span>
<h3>{prev.title}</h3>
</Link>
)}
{next && (
<Link to={next.url}>
<span>Next</span>
<h3>{next.title}</h3>
</Link>
)}
</div>
That's pretty much it, with a little CSS
flair you can make it look niceπ
For Reference
I've used this same logic on my gatsby blog as well. For reference, take a look at my article template and my gatsby-node.js file.
Top comments (0)