R note

Gatsby + Airtableサイトにカテゴリを追加した(1)

GatsbyJSAirtable

Gatsby + Airtableでゼロから作っているこのサイト(R note)にノートのカテゴリを追加したので手順を記録しておきます。これがベストなやり方かは置いておいて、とりあえず、こんなやり方もあるよということで。ご参考までに。

Airtableの準備

Airtableの準備はすごく簡単でした。

  1. 「category」テーブルを追加
  2. 記事用の「entry」テーブルに「category」テーブルを参照するフィールドを追加

これだけです。Airtable便利ですね。

1. categoryテーブル

categoryテーブル

categoryテーブルは以下の項目で構成されてます。

  • catname: カテゴリ名
  • slug: リンク用の文字列
  • entry: カテゴリに登録される記事(自動で追加される)
  • catstatus: ステータス。オン・オフできるように念のため

2. entryテーブル

entryテーブルにcategoryフィールドを追加してcategoryテーブルにリンクします。フィールドを追加する際に「Link to another record」から「category」テーブルを選びます。

AirtableのLink to another recordオプション

これでcategoryを選ぶ際に以下のようにcategoryテーブルのレコードから選べるようになります。

カテゴリの選択画面

ちなみに、entryテーブルにcategoryフィールドを追加する際にcategoryテーブルにリンクするとcategoryテーブルに「entry」というフィールドが自動で作成されます。

Airtableの準備はこれで完了です。

Gatsbyでやったことの概要

まずはざっくり概要から。Gatsbyサイトでは以下の作業を行いました。

  1. 記事ページでカテゴリ表示を追加
  2. 各カテゴリの記事一覧ページを追加
  3. カテゴリ一覧ページを追加

1. 記事ページでカテゴリ表示を追加

下の画像のように日時の下にカテゴリを追加しました。

記事ページのカテゴリ表示

2. 各カテゴリの記事一覧ページを追加

カテゴリごとの記事一覧が見られるページを追加しました。たとえば、GatsbyJSカテゴリにある記事は以下のような感じです。

3. カテゴリ一覧ページを追加

すべてのカテゴリが見られる一覧ページを作りました。

いまのところカテゴリの記事一覧ページの最下部からしか遷移できませんが、今後、ナビゲーションを追加する際に何か考えたいと思います。

以下、詳細です。

1. gatsby-source-airtableにテーブルを追加

gatsby-config.jsのプラグインのセクションのgatsby-source-airtable部分に、新たに追加した「category」テーブルを追加します。それから「entry」テーブルと「category」テーブルをリンクするためにtableLinks: ['category']を「entry」テーブルの項目に追加します。

{
  resolve: `gatsby-source-airtable`,
  options: {
      apiKey: `${process.env.GATSBY_AIRTABLE_APIKEY}`,
      tables: [
        {
            baseId: 'ベースのID',
            tableName: 'entry',
            tableView: 'Published',
            queryName: '',
            mapping: { 'body': 'text/markdown' },
            tableLinks: ['category',],        },
        {          baseId: 'ベースのID(上のと同じやつ)',          tableName: 'category',          tableView: 'Active',        }      ]
  },
},

ベースのIDはAirtableのAPI documentationのページで確認できます。

2. 既存のGraphQLクエリにフィルターを追加

gatsby-source-airtableのオプションに「category」テーブルを追加したことで、GraphQLで書いたクエリで両方のテーブルのデータが読み込まれるようになります。GraphiQLで参照してみるとわかりますが、「entry」テーブルのレコードの後に「category」テーブルのレコードが追加されるイメージです。

  • entryテーブルのレコード1
  • entryテーブルのレコード2
  • entryテーブルのレコード3...
  • categoryテーブルのレコード1
  • categoryテーブルのレコード2...

「entry」のデータのみを読み込むためにはクエリにフィルターを追加します。

たとえば、以下はトップページで記事一覧を書き出すためのクエリの一部ですが、allAirtableの部分にフィルターを追加しました。

export const query = graphql`
   query {
      allAirtable(
         sort: { fields: [data___date], order: DESC },
         filter: { table: {eq: "entry"}},      ) {
         totalCount
         edges {
            node {
               data {
                  slug
                  title
                  date(formatString: "YYYY/MM/DD @HH:mm")
               }
            }
         }
      }
   }
`

3. 記事ページにカテゴリを追加

記事ページのテンプレートにカテゴリを表示させるために以下を行いました。

a. GraphQLクエリの編集

表示する内容をAirtableから取得するために、まずはGraphQLクエリに必要な項目を追加します。ここでは表示するためのカテゴリ名(catname)とリンク用のテキスト(slug)を、entryテーブルからリンクされたcategoryテーブルから取得しています。

export const query = graphql`
  query($slug: String!){
    airtable(data: {slug: { eq: $slug }}) {
      data {
        title
        body {
          childMarkdownRemark {
            html
            excerpt
          }
        }
        date(formatString: "YYYY/MM/DD @HH:mm")
        slug
        category {          data {            catname            slug          }        }      }
    }
  }
`

gatsby-source-airtableプラグインでリンク設定した「category」テーブルが「entry」テーブルに入れ子になるイメージですね。

b. 表示内容のHTMLを構築

表示する内容のHTMLをGraphQLで取得したデータから構築します。カテゴリは複数登録されている可能性もあるので、JavaScriptのmapメソッドを使ってデータを取得しています。

    const post = this.props.data

    let categories
    if(post.airtable.data.category != null){
      categories = post.airtable.data.category.map(({ data }, index) => (        <span className={styles.tags} key={index}><Link to={`/category/${data.slug}/`}>{data.catname}</Link></span>
      ))
    }

c. カテゴリ表示部分のHTMLを追加

上で加工した表示内容でカテゴリを表示するために、以下のHTMLを追加しました。{category}の部分で上で構築した内容を挿入しています。

<p className={styles.postCategories}>カテゴリ: {categories}</p>

あとカテゴリ表示用のスタイルも追加しましたが、ここでは省略します。 これで記事ページでのカテゴリの表示の追加は完了です。

...

と、ここまで書いて、カテゴリが空の場合の処理を忘れていたことに気づきました。ということで、一時中断します。

長くなってしまったし、こちらをパート1として、残りはパート2書こうと思います書きました。


(追記) 先ほどのコードを以下のように修正しました。

まずは表示内容を構築する部分にHTMLをすべて入れ込みました。

    const post = this.props.data

    let categories
    if(post.airtable.data.category != null){
      categories = post.airtable.data.category.map(({ data }, index) => (
        <span className={styles.tags} key={index}><Link to={`/category/${data.slug}/`}>{data.catname}</Link></span>
      ))
    }
    categories = <p className={styles.postCategories}>カテゴリ: {categories}</p>

で、表示部分を以下に変更しました。これで{categories}が空だったら何も表示されないようになります。

{categories}

やってみての感想 => Gatsbyいいね!

すべて初めてやったことだったので結構時間がかかりました。でも、Gatsbyはすごく便利だと実感してます。すごく柔軟にいろんな機能やコンテンツを追加できそうです。JavaScriptとReactを知ってる人ならサクっといろいろなことができて、むちゃくちゃ便利なはずです。

Gatsbyは最終的なアウトプットが静的なHTMLでパフォーマンスもほぼ自動で最適化されていてサクサク動くのもすごく気に入っています。

Gatsbyいいなぁ。いい。可能性を感じます。