Contentful+Gatsbyアプリで記事のタグを表示するまで。

Contentful+Gatsbyアプリで記事一覧ページを作成中に、記事にタグをつけたくなったので、その備忘録。

Contentful側の準備

Contentful側でどういう準備や処理が必要かは、こちらの記事が大変参考になった。

Contentfulのレコード数を消費するので、いつ無料プラン枠を飛び出してしまうか心配だけど、僕以外の記事執筆者が簡単に動的にタグを追加できる様にするにはこの方法がベターではある。

僕のContent Modelは下記のような感じ。一番下にTagsを追加。


ちなみにContentfulの記事編集画面でタグ付けしてみるとこんな感じ。


複数のタグを付けられるし、何も付けないということもできる。

Gatsby側の実装

まずGraphQLのクエリは下記のようにしている。

export const query = graphql`
    query BlogArticleQueryTop {
        allContentfulBlogArticle(filter: {node_locale: {eq: "ja-JP"}}) {
            edges {
                node {
                    id
                    title
                    slug
                    content {
                        content
                    }
                    thumbnail {
                        file {
                            url
                        }
                    }
                    tags {
                        name
                        slug
                    }
                    createdAt
                }
            }
        }
    }
`;

僕の場合、Contentfulのlocales設定で複数の言語が許容しているので、フィルタリング(filter: {node_locale: {eq: "ja-JP"}})を行って、記事が重複して取得されない様にしている。

Tagsの要素としてname(タグ表記名)とslug(タグのURL用)を取得している。

で、肝心の記事表示部分。今回は記事の一覧ページでの表示を想定しているので、map()関数で記事の配列を展開していて、その中でさらにTagsの配列を展開する形にしている。

const PostBasic = ({ postData }) => (
  postData.map(({ node: post }) => (
  <div className="post-basic-item">
    <img src={post.thumbnail.file.url} alt="Slide1" className="thumbnail" />
    <div className="post-basic-textblock">
      <p className="post-basic-postedat">{post.createdAt}</p>
      <h3><Link to={`/post/${post.slug}`}>{post.title}</Link></h3>
      <p>{post.content.content}</p>
      <div className="post-basic-catbox">
        <span className="post-basic-catname">{post.category}</span>
        <ul className="post-basic-tags">
        {post.tags && post.tags.map(({ name, slug }) =>
          <li>{name}: {slug}</li>
          )
        }
        </ul>
      </div>
    </div>
  </div>
  ))
)

フロントでの見た目は下記のようになる。


上記コードの中でタグ表示部分を抜き出してみる。

{post.tags && post.tags.map(({ name, slug }) =>
  <li><Link to={`/post/${slug}`}>#{name}</Link></li>
  )
}

ポイントとしては、記事によってはタグを持たないケースがあるので、論理演算子( eg. aaa && bbb )によって、要素(この場合はpost.tagsを指す)がnullだったら、配列の展開処理(map)を実行しないようにしている。

上記は人様に教えていただいたんだけど、説明してもらうまで記事がタグを持たないケースがあることに気がつかず、

TypeError: Cannot read property 'map' of null

のエラーが何故に発生するのか4時間くらいハマってしまった・・・。

アプリがだんだん形になりつつあるので、近いうちにこのブログもContentfulに移行したいな〜。

Written by Ryo Konishi