Gatsbyに前後の記事へのリンクを追加する方法
2021.11.28
この記事は約3分で読めます
目次
この記事の筆者:三好アキ
🔹 専門用語なしでプログラミングを教えるメソッドに定評があり、1200人以上のビギナーを、最新のフロントエンド開発入門に成功させる。
🔹 Amazonベストセラー1位を複数回獲得している『はじめてつくるReactアプリ with TypeScript』著者。
Amazon著者ページはこちら → amazon.co.jp/stores/author/B099Z51QF2
React、Next.js、TypeScriptなどのお役立ち情報や実践的コンテンツを、ビギナー向けにかみ砕いて無料配信中。登録はこちらから → 無料メルマガ登録
前後の記事へのリンク
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に興味のある人は次の記事も参考にしてください。
メルマガ配信中
(from 三好アキ/エンジニア)
React、Next.js、TypeScriptなど最新のウェブ開発のお役立ち情報を、ビギナー向けにかみ砕いて無料配信中。
(*配信はいつでも停止できます)