Gatsbyに前後の記事へのリンクを追加する方法
2021.11.28
この記事は約3分で読めます
目次

この記事の筆者:三好アキ
🟢 専門用語なしでプログラミングを教えるメソッドに定評があり、1200人以上のビギナーを、最新のフロントエンド開発入門に成功させる。
🟢『はじめてつくるReactアプリ with TypeScript』、『動かして学ぶ!Next.js/React開発入門(翔泳社/*韓国でも出版)』著者。
▼ Amazon著者ページはこちら
amazon.co.jp/stores/author/B099Z51QF2
前後の記事へのリンク
Jamstackサイト制作でよく使われるGatsbyに、前後の記事へと移動する仕組みを追加します。
本記事は、まず最初にGatsbyサイトに最もベーシックなブログ機能を実装し、そこに前後の記事へのリンクを追加するという流れです。
ロジック部分の説明だけなので、スタイルは各自お好みで適用してください。
なお、本記事ではGatsbyの最新バージョン(2021年11月時点)であるv4を使いますが、v2でもv3でも本記事と同じコードで前後の記事へと移動する仕組みを実装できます。
なおページネーション機能は、こちらの記事を参考にしてください。
ベーシックなブログ機能の作成
まずGatsbyのスターターサイトに、マークダウンのブログ機能を追加しましょう。
最初にスターターサイトをダウンロードするので、ターミナルで以下のコマンドを実行します。
npx gatsby new gatsby-starter-default https://github.com/gatsbyjs/gatsby-starter-default次にブログ記事を一覧表示するblog.js、個別記事を表示するsingleBlog.jsを作ります。
まずはblog.jsから始めます。
├──pages
│       ├── 404.js   
│       ├── blog.js    ←追加
│       ├── index.js  
│       ├── pages-2.js   
│       ├── using-ssr.js  
│       └── using-typescript.tsx 
次のコードを書きます。
// blog.js
import * as React from "react"
import { graphql, Link } from "gatsby"
 
const Blog = (props) => {
    return (
        <div>    
            <h1>ブログページ</h1>
            {props.data.allMarkdownRemark.edges.map((singleBlog, index) => 
                <div key={index}>              
                    <h2><Link to={`/blog${singleBlog.node.fields.slug}`}>{singleBlog.node.frontmatter.title}</Link></h2>       
                    <p>{singleBlog.node.frontmatter.date}</p>      
                </div>              
            )}  
        </div>  
    )
}
export default Blog
export const query = graphql`
    query BlogQuery { 
        allMarkdownRemark(
            sort: {fields: frontmatter___id, order: DESC}     
        ) {
            edges {
                node {
                    fields {
                        slug
                    }
                    frontmatter {
                        date
                        summary
                        id
                        title
                    }
                }
            }
        }
    }
`singleBlog.jsをtemplatesフォルダ内に作ります。
├──templates 
│       ├── singleBlog.js    ←追加  
│       └── using-dsg.js
次のコードを書きます。
// singleBlog.js
import * as React from "react"
import { graphql } from "gatsby"
 
const SingleBlog = (props) => {
    return (
        <div>                       
            <h1>{props.data.markdownRemark.frontmatter.title}</h1> 
            <p>{props.data.markdownRemark.frontmatter.date}</p> 
            <div dangerouslySetInnerHTML={{ __html: props.data.markdownRemark.html }} />  
        </div>     
    )
}
export default SingleBlog
export const query = graphql`
    query SingleBlogQuery($slug: String!) {
        markdownRemark(fields: { slug: { eq: $slug } }) {
            frontmatter {
                date
                title
                summary
                id
            }
            html
        }
    }
`次に、ブログ記事のマークダウンファイルを収納するフォルダをsrc内に作ります。
├──src
│  ├── components    
│  ├── data    ←追加
│  ├── images  
│  ├── pages   
│  └── templates    
data内には6つのマークダウンファイルを作ります。
├── data
│      ├── first.md    
│      ├── second.md  
│      ├── third.md   
│      ├── fourth.md  
│      ├── fifth.md   
│      └── sixth.md    それぞれのマークダウンファイルには、下のように基本的な情報を書きます。
// first.md
---
id: "1"
title: "記事1"
date: "2021-06-21"
summary: "記事1の要約"
---
1つ目の記事。// second.md
---
id: "2"
title: "記事2"
date: "2021-06-22"
summary: "記事2の要約"
---
2つ目の記事。// third.md
---
id: "3"
title: "記事3"
date: "2021-06-23"
summary: "記事3の要約"
---
3つ目の記事。// fourth.md
---
id: "4"
title: "記事4"
date: "2021-06-24"
summary: "記事4の要約"
---
4つ目の記事。// fifth.md
---
id: "5"
title: "記事5"
date: "2021-06-25"
summary: "記事5の要約"
---
5つ目の記事。// sixth.md
---
id: "6"
title: "記事6"
date: "2021-06-26"
summary: "記事6の要約"
---
6つ目の記事。これでブログのデータと、それを表示する部分ができました。
次は表示するための仕組みづくりです。
ブログ機能に必要なプラグインをインストールします。
npm install gatsby-transformer-remarkこれと、デフォルトですでに入っているgatsby-source-filesystemをgatsby-config.jsに追加します。
// gatsby-config.js
module.exports = {
  siteMetadata: {
     
      ...
  plugins: [
    `gatsby-plugin-react-helmet`,
    `gatsby-plugin-image`,
    // ⬇ 追加
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: `data`,
        path: `${__dirname}/src/data`,
      },
    },
    `gatsby-transformer-remark`,
    // ⬆ 追加
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: `images`,
        path: `${__dirname}/src/images`,
      },
    },
    `gatsby-transformer-sharp`,
    ...
gatsby-node.jsに、上で作ったコンポーネントにマークダウンファイルを流し込むためのコードを追加します。
// gatsby-node.js
// ⬇ 削除
exports.createPages = async ({ actions }) => {
  const { createPage } = actions
  createPage({
    path: "/using-dsg",
    component: require.resolve("./src/templates/using-dsg.js"),
    context: {},
    defer: true,
  })
}
// ⬆ 削除
const path = require(`path`)
const { createFilePath } = require(`gatsby-source-filesystem`)
exports.onCreateNode = ({ node, getNode, actions }) => {
    const { createNodeField } = actions
  
    if (node.internal.type === `MarkdownRemark`) {
        const slug = createFilePath({ node, getNode })   
        createNodeField({         
            node,                   
            name: `slug`,           
            value: slug,            
        })
    }
}
exports.createPages = async ({ graphql, actions }) => {  
    const { createPage } = actions   
    const result = await graphql(`              
        query {
            allMarkdownRemark {
                edges {
                    node {
                        fields {
                            slug
                        }
                    }
                }
            }
        }
    `)
  
    result.data.allMarkdownRemark.edges.forEach(({ node }) => {
        createPage({
            path: `blog${node.fields.slug}`,
            component: path.resolve(`./src/templates/singleBlog.js`),
            context: {
                slug: node.fields.slug,
            },
        })
    })
}ここまで加えた変更をすべて保存します。
gatsby developでGatsbyを起動し、http://localhost:8000/blogをブラウザで開くと、ブログ機能が追加されているのがわかります。
これ以降、本題の前後のページへと移動する機能を追加していきます。
実装に必要なもの3つ
前後の記事へのリンク実装には次の3つが必要です。
1 gatsby-node.jsに前後の記事の情報を取得するGraphQLクエリを追加
2 取得した前後の記事の情報をsingleBlog.jsコンポーネントに渡す
3 prevNext.jsコンポーネント
それでは順番通りに作っていきます。
gatsby-node.jsにGraphQLクエリを追加
次のコードをgatsby-node.jsに追加します。
// gatsby-node.js
const path = require(`path`)
const { createFilePath } = require(`gatsby-source-filesystem`)
exports.onCreateNode = ({ node, getNode, actions }) => {
    const { createNodeField } = actions
  
    if (node.internal.type === `MarkdownRemark`) {
        const slug = createFilePath({ node, getNode })   
        createNodeField({         
            node,                   
            name: `slug`,           
            value: slug,            
        })
    }
}
exports.createPages = async ({ graphql, actions }) => {  
    const { createPage } = actions   
    const result = await graphql(`              
        query {
            allMarkdownRemark (sort: { order: ASC, fields: [frontmatter___id] }){    // 追加
                edges {
                    node {
                        fields {
                            slug
                        }
                    }
                    // ⬇ 追加
                    next {
                        frontmatter {
                            title
                        }
                        fields {
                            slug
                        }
                    }
                    previous {
                        fields {
                            slug
                        }
                        frontmatter {
                            title
                        }
                    }
                    // ⬆ 追加
                }
            }
        }
    `)
  
    result.data.allMarkdownRemark.edges.forEach(({ node, next, previous }) => {    // 追加
        createPage({
            path: `blog${node.fields.slug}`,
            component: path.resolve(`./src/templates/singleBlog.js`),
            context: {
                slug: node.fields.slug,
                next,       // 追加
                previous,   // 追加
            },
        })
    })
}いま追加したコードは、まずGraphQLで前後の記事のタイトル(title)とパス情報(slug)を取得しています。
次にcontextの中にそれを置きます。
これによって、singleBlog.jsからpageContextによってそのデータにアクセスできます。
なおallMarkdownRemarkに追加したコードは、前後の記事の順番を整えるためのものです。
        
前後の記事の情報をsingleBlog.jsに渡す
context内のデータはpageContextで渡されるので、次のコードを追加します。
// singleBlog.js
import * as React from "react"
import { graphql } from "gatsby"
import PrevNext  from "../components/prevNext"   // 追加
 
const SingleBlog = (props) => {
    return (
        <div>                       
            <h1>{props.data.markdownRemark.frontmatter.title}</h1> 
            <p>{props.data.markdownRemark.frontmatter.date}</p> 
            <div dangerouslySetInnerHTML={{ __html: props.data.markdownRemark.html }} />  
            <PrevNext pageContext={props.pageContext} />  // 追加
        </div>     
    )
}
export default SingleBlog
export const query = graphql`
    query SingleBlogQuery($slug: String!) {
        markdownRemark(fields: { slug: { eq: $slug } }) {
            frontmatter {
                date
                title
                summary
                id
            }
            html
        }
    }
`最後に、いま追加したprevNext.jsコンポーネントを作ります。
prevNext.jsコンポーネント
prevNext.jsをcomponentsフォルダに作ります。
src
.
.
├── components    
│      ├── header.js
│      ├── layout.css
│      ├── layout.js  
│      ├── prevNext.js    ←追加    
│      └── seo.js
.
.そこに次のコードを書きます。
// prevNext.js
import * as React from "react"
import { Link } from 'gatsby'
const PrevNext =({ pageContext }) => {
    const { previous, next } = pageContext
    return (
        <div>
            {previous && 
                <Link to={`/blog${previous.fields.slug}`}>
                    <h3>{previous.frontmatter.title}</h3>
                </Link>
            }
            {next && 
                <Link to={`/blog${next.fields.slug}`}>
                    <h3>{next.frontmatter.title}</h3>
                </Link>
            }
        </div>
    )
}
export default PrevNext変更を保存してgatsby developでGatsbyを起動させ、ブラウザでhttp://localhost:8000/blogに表示されている記事を開くと、前後の記事へと移動する機能が追加されているのがわかります。
本記事では細かい説明を省略して足早に解説しましたが、Gatsbyについてよりくわしく知りたい方は、拙著「はじめてつくるGatsbyサイト」を参考にしてください。
なお、Gatsbyブログの記事一覧ページ(blog.js)に表示される記事数を制限するページネーション機能については、こちらの記事を参考にしてください。
その他、Gatsbyに興味のある人は次の記事も参考にしてください。

🟩 フロントエンド開発者入門ガイド【無料配布中】
最初にこれが知りたかった!
フロントエンド初心者が必ず押さえておきたい ― 『挫折しない勉強法』とその具体的ステップ、無料配布中。
(*名前不要・メールアドレスだけで受け取り可能です)
 
     
     
    

