Link prev/next articles dynamically on your gatsby blog
Tags: gatsby, react, blog
Published: 2020-01-13 15:47:33

## Introduction

Linking your next and previous article doesn't require any packages to be installed, infact it's quite simple to implement.

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/36vxaty7a2dhdpbz3qkv.png)

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 -

```js
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.

```js
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

```js
articles.forEach(({ node }, index) => {
   createPage({
      ...
      context: {
         ...
         prev: index === 0 ? null : articles[index - 1].node
      }
   })
})
```

### For next article

```js
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

```js
const Article = ({ pageContext }) => {}
```

Let's extract details of prev/next and save them into variables.

### For previous article
```js
const prev = pageContext.prev
   ? {
         url: `/blog/${pageContext.prev.fields.slug}`,
         title: pageContext.prev.frontmatter.title
      }
   : null
```

### For next article
```js
const next = pageContext.next
   ? {
         url: `/blog/${pageContext.next.fields.slug}`,
         title: pageContext.next.frontmatter.title
      }
   : null
```

Now render them on your article using `jsx`.

```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](https://github.com/prvnbist/portfolio/blob/466ab103bc76664896dcbb02ba4bac02099cbfc3/src/templates/blog/index.jsx#L33 "article template") and my [gatsby-node.js](https://github.com/prvnbist/portfolio/blob/466ab103bc76664896dcbb02ba4bac02099cbfc3/gatsby-node.js#L17 "gatsby-node.js") file.