Link prev/next articles dynamically on your gatsby blog
Jan 13, 2020- gatsbyjs
- pagination
- blog
- articles
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 -
1const result = await graphql(`2 query {3 // if you're using just markdown, replace allMdx with allMarkdownRemark4 allMdx(sort: { order: DESC, fields: [frontmatter___date] }) {5 edges {6 node {7 fields {8 slug9 }10 frontmatter {11 title12 }13 }14 }15 }16 }17`)
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.
1const 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
1articles.forEach(({ node }, index) => {2 createPage({3 ...4 context: {5 ...6 prev: index === 0 ? null : articles[index - 1].node7 }8 })9})
For next article
1articles.forEach(({ node }, index) => {2 createPage({3 ...4 context: {5 ...6 next: index === articles.length - 1 ? null : articles[index + 1].node7 }8 })9})
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
1const Article = ({ pageContext }) => {}
Let's extract details of prev/next and save them into variables.
For previous article
1const prev = pageContext.prev2 ? {3 url: `/blog/${pageContext.prev.fields.slug}`,4 title: pageContext.prev.frontmatter.title,5 }6 : null
For next article
1const next = pageContext.next2 ? {3 url: `/blog/${pageContext.next.fields.slug}`,4 title: pageContext.next.frontmatter.title,5 }6 : null
Now render them on your article using jsx
.
1<div>2 {prev && (3 <Link to={prev.url}>4 <span>Previous</span>5 <h3>{prev.title}</h3>6 </Link>7 )}8 {next && (9 <Link to={next.url}>10 <span>Next</span>11 <h3>{next.title}</h3>12 </Link>13 )}14</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 and to see it in action, just scroll a little😅