2022/11/03

microCMS+Gatsby製ブログでタグ一覧に件数をつける

ウェブ開発
microCMSGatsby

さて、最近ブログを少しずつ改良しています。
このブログにはタグおよびカテゴリを記事ごとに付与しています。タグは1記事に複数、カテゴリは1記事ひとつまでのルールです。(あまり整理はうまくいってませんが..)

さて、このタグおよびカテゴリは一覧表示をブログ中で行っているのですが、よく見る

  • タグの中に記事数を表示させる
  • 記事の多い順にタグを並べる

ということをしたいと考えました。

このブログはmicroCMSとGatsbyで構築しており、タグやカテゴリもmicroCMSのただのコンテンツの一種です。
microCMSのAPIは、参照しているコンテンツはできますが、被参照されているコンテンツを取得することができません。(もしできたら教えてください)



というわけで強引に実装していきましょう。

前提

ブログにカテゴリ、タグを設定しており、gatsbyでgatsby-source-microcmsを利用していること。
gatsby-config.jsでcategory, tagの設定を以下のように行っており、GraphQLにMicrocmsCategory, MicroCMSTagがあること。

    {
      resolve: "gatsby-source-microcms",
      options: {
        apiKey: process.env.API_KEY,
        serviceId: 'your_subdomain',
        apis: [
          {
            endpoint: "blog",
          },
          {
            endpoint: "category",
          },
          {
            endpoint: "tag",
          },
        ],
      },


実装

せっかくGatsbyとmicroCMSを使っているので、できるだけGraphQLに乗っかりたいところです。
gatsbyではGatsby Node APIの中で、GraphQLスキーマの作成中に呼び出されるsetFieldsOnGraphQLNodeTypeの設定が可能です。
これにより、GraphQLの値を追加することができます。

gatsby-node.js内に以下を記述

exports.setFieldsOnGraphQLNodeType = require('./src/setFieldsOnGraphQLNodeType');


以下

const { GraphQLInt } = require("gatsby/graphql");
const axios = require('axios');

module.exports = async args => {
  //カテゴリ一覧に件数を追加
  const apiKey =  process.env.API_KEY;
  if(args.type.name === "MicrocmsCategory"){
    return {
      blogsCount: {
        type: GraphQLInt,
        args: {},
        resolve: async (source, fieldArgs) => {
          const res = await axios.get('https://your-subdomain.microcms.io/api/v1/blog?filters=category[equals]'+source.categoryId, {headers: {'X-MICROCMS-API-KEY': apiKey}});
          return res.data.totalCount;
        }
      }
    }
  }
  //カテゴリ一覧に件数を追加
  if(args.type.name === "MicrocmsTag"){
    return {
      blogsCount: {
        type: GraphQLInt,
        args: {},
        resolve: async (source, fieldArgs) => {
          const res = await axios.get('https://your-subdomain.microcms.io/api/v1/blog?filters=tags[contains]'+source.tagId, {headers: {'X-MICROCMS-API-KEY': apiKey}});
          return res.data.totalCount;
        }
      }
    }
  }

  return {}
};

GraphQLの処理に介入する以上GraphQLは使えない(はず...)ので、axiosでmicroCMS APIを叩く形に。

カテゴリ一覧を表示するコンポーネント内でblogsCountが参照できるようになりました。
下記のようにソート及び表示を行います。

export const Categories = ({ categories }) => {
    return (
        <Box sx={{paddingTop: "1em", marginBottom: "1em"}}>
            <Card sx={{padding: ".5em"}}>
                <Typography sx={{fontSize: 18, fontWeight: "bold"}} color="text.secondary" gutterBottom>
                    カテゴリ一覧
                </Typography>
            {categories.sort((a,b)=>b.blogsCount - a.blogsCount).map(category => (
                <Chip key={category.categoryId} label={category.blogsCount ? category.name + "(" + category.blogsCount + ")" : category.name} icon={<Article />} sx={{lineHeight: 2, margin: ".25em .25em .25em 0", padding: ".3em .5em .3em .5em ", "&:hover": { backgroundColor: "#ccc"}}} onClick={event => {
                    event.preventDefault()
                    navigate("/blog/category/" + category.categoryId)
                }}>
                </Chip>
            ))}
            </Card>
        </Box>
    )
}


これで、

結果

適用前


適用後

綺麗にカテゴリとタグの中身が並びました。

問題点

この実装は要するにN+1問題を抱えているので、カテゴリ一覧をGraqhQLで取得しようとするとカテゴリ数分のAPIリクエストが発生します。
そのため、gatsby buildが遅くなります。
根本的には、microCMSのAPIが被参照を返してくれる仕組みを作ってくれないと解決は難しいと思われます。

今回の場合はどの画面からでも結果生成されるコンポーネントの内容はいっしょなので、Gatsby/Reactでうまくキャッシュできないか検討してみたいと思います。

カテゴリ一覧

雑記(13)
ウェブ開発(8)
IoT(6)
買い物(3)
カメラ(1)
ガジェット
セキュリティ
自転車
PC

タグ一覧

運動記録(9)
Gatsby(6)
Switchbot(5)
React(4)
microCMS(3)
目標(3)
靴(1)
ねこ(1)
HTML(1)
椅子(1)
α7R V(1)
MUI(1)
三脚
生活雑貨
カメラ小物
家電
© 2025 うすかん, Built with Gatsby