筋肉チョットデキル

サイト内記事へのサムネ付きリンクを表示するコンポーネントを作った

2020年05月19日

技術ブログGatsby

記事内に同じブログ内の記事へのリンクを貼ることがあって、リッチに表示できたらなぁと思ったのでやってみた。

↓ こんなの

Gatsby
MDX
Chakra UI

2020年05月16日

MDX の紹介と、当ブログで使っているコンポーネントを紹介していきます 💪 MDX について 基本的に当ブログの記事は Markdown 形式で書いているのですが、拡張子は .md…

使い方

マークダウンファイル(.mdx)内に以下のように書きます!

mdx
## マッチョ
**マッチョ**はいいぞ!
**鏡が大好き**だぞ!
こんな感じでマークダウンの記述があるぞ!
さあ出るぞ
コンポーネントが出るぞ
でた!!
<PostLink to='/blog/what-is-mdx' />

😄

パスを指定するだけだから簡単だ!

コンポーネント失敗例

コンポーネントのソースコードは以下の通りです。

PostLink.jsx
import React from 'react';
import { useStaticQuery, graphql, Link } from 'gatsby';
import { Box,Flex, Text } from '@chakra-ui/core';
import Img from 'gatsby-image';
import Tags from '../Tags';
const PostLink = ({ to, ...props }) => {
const { mdx } = useStaticQuery(graphql`
{
mdx(fields: { slug: { eq: ${to} } }) {
frontmatter {
cover {
childImageSharp {
fluid {
...GatsbyImageSharpFluid
}
}
}
tags
description
date(formatString: "YYYY年MM月DD日")
}
excerpt(pruneLength: 100)
}
}
`);
if (!mdx) return null;
return (
<Flex justify='center'>
<Link to={mdx.fields.slug}>
<Box
maxW='sm'
p='2'
borderWidth='1px'
rounded='lg'
overflow='hidden'
{...props}
>
<Img
fluid={mdx.frontmatter.cover.childImageSharp.fluid}
alt='post cover'
/>
<Tags plain post={mdx} fontSize='xs' />
<Text textAlign='right'>{mdx.frontmatter.date}</Text>
<Box p='4'>{mdx.frontmatter.description || mdx.excerpt}</Box>
</Box>
</Link>
</Flex>
);
};

と言いたいところなんですが、、
GraphQLのクエリ部分でエラーが出てしまいます。

String interpolation is not allowed in graphql tag

文字列の埋め込みはできない。
useStaticQueryは文字通り静的なクエリで動的には生成出来ないようです。

コンポーネント成功例

気を取り直して別の方法で!💪

コンポーネントのソースコードは以下の通りです。

PostLink.jsx
import React from 'react';
import { useStaticQuery, graphql, Link } from 'gatsby';
import { Box,Flex, Text } from '@chakra-ui/core';
import Img from 'gatsby-image';
import Tags from '../Tags';
const PostLink = ({ to, ...props }) => {
const { allMdx } = useStaticQuery(graphql`
{
allMdx {
edges {
node {
frontmatter {
cover {
childImageSharp {
fluid {
...GatsbyImageSharpFluid
}
}
}
tags
description
date(formatString: "YYYY年MM月DD日")
}
excerpt(pruneLength: 100)
fields {
slug
}
}
}
}
}
`);
const mdx = allMdx.edges.find(edge => edge.node.fields.slug === to)?.node;
if (!mdx) return null;
return (
<Flex justify='center'>
<Link to={mdx.fields.slug}>
<Box
maxW='sm'
p='2'
borderWidth='1px'
rounded='lg'
overflow='hidden'
{...props}
>
<Img
fluid={mdx.frontmatter.cover.childImageSharp.fluid}
alt='post cover'
/>
<Tags plain post={mdx} fontSize='xs' />
<Text textAlign='right'>{mdx.frontmatter.date}</Text>
<Box p='4'>{mdx.frontmatter.description || mdx.excerpt}</Box>
</Box>
</Link>
</Flex>
);
};
export default PostLink;

内容は以下の流れです。

  • useStaticQueryで全MDXを取得
  • 全MDXの中から、指定するMDX1つを探す
  • 見つからなければ何も表示しない
  • 見つかれば表示

です。

それではコードと共に詳しく見ていきましょう。

useStaticQueryで全MDXを取得

useStaticQueryはGraphQLクエリを受け取って、データを返すhookです。

該当コードはこちらです。

const { allMdx } = useStaticQuery(graphql`
{
allMdx { // すべてのMDX
edges {
node {
frontmatter {
cover { // サムネ画像情報
childImageSharp {
fluid {
...GatsbyImageSharpFluid
}
}
}
tags // タグ設定
description // description設定
date(formatString: "YYYY年MM月DD日") // 日付設定、フォーマットはYYYY年MM月DD日
}
excerpt(pruneLength: 100) // Gatsbyが抜粋した冒頭部分。descriptionが設定されてなければこちらを使う
fields {
slug // スラッグ。任意のmdxを見つけ出すために使う
}
}
}
}
}
`);

useStaticQueryについて詳しくはこちらをどうぞ!

全MDXの中から、指定するMDX1つを探す

MDXがもつslug情報と、propsのto

<PostLink to='/blog/what-is-mdx' />

が一致するものを探します。

該当コードはこちらです。

const mdx = allMdx.edges.find(edge => edge.node.fields.slug === to)?.node;

MDX見つからなければ何も表示しない

該当コードはこちらです。

if (!mdx) return null;

MDXが見つかれば表示

該当コードはこちらです。

return (
<Flex justify='center'>
<Link to={mdx.fields.slug}>
<Box
maxW='sm'
p='2'
borderWidth='1px'
rounded='lg'
overflow='hidden'
{...props}
>
<Img
fluid={mdx.frontmatter.cover.childImageSharp.fluid}
alt='post cover'
/>
<Tags plain post={mdx} fontSize='xs' />
<Text textAlign='right'>{mdx.frontmatter.date}</Text>
<Box p='4'>{mdx.frontmatter.description || mdx.excerpt}</Box>
</Box>
</Link>
</Flex>
);

画像は少しでも表示速度が速くなるように、gatsby-imageを使っています。

タグと日付を表示し、テキストはdescription(descriptionが未定義ならexcerpt)を表示しています。

ちなみにfrontmatterは以下のように各記事で定義しているもので、excerptはGatsbyが抜粋した冒頭部分です。

---
title: サイト内記事へのサムネ付きリンクを表示するコンポーネントを作った
date: '2020-05-19T21:00:00Z'
description: ''
featured: false
cover: ./cover.jpeg
tags:
- Gatsby
---

これでコンポーネントの出来上がりです!!

🎉🎉

今回みたいにこんな風に書きたいなぁってのが実現できるし、それが勉強にもなるし、自分の技術ブログをもつのよきだなぁ!


岡本 侑貴@筋肉チョットデキル

筋肉バカ。筋トレしてコード書いて、毎日幸せに生きてる。ボディビルにドハマリ。2021年東京オープンボディビル選手権で最高の身体に仕上げてつよつよエンジニアになる!!

Made with Gatsby& ChakraUi

Yuuki Okamoto • 2020