ちょっとした技術メモを忘れないうちに書いていく

GatsbyJS マークダウンにコンポーネントを表示する

2019-07-10

MarkdownにReactのコンポーネントを記述して処理できるようにする


unsplash のランダム画像を表示するコンポーネントを作成し、マークダウン内で unsplash 要素として使用できるようにします。

必要なプラグイン

以前使ったマークダウンの表示に必要なプラグイン 詳しくはこちら

  • gatsby-source-filesystem
  • gatsby-transformer-remark

今回必要なプラグイン

  • rehype-react マークダウンの要素を変換する React のプラグイン

  • gatsby-remark-component マークダウン表示時の p タグを div タグに変換する (変換しないと validateDOMNesting アラートがでてしまう)

npm install --save rehype-react gatsby-remark-component

まずはマークダウンファイルをそのまま表示

マークダウンファイルを作成

プロジェクトディレクトリに data ディレクトリを作成し、file1.md を作成する

## マークダウンファイルの内容

AAAABBBBCCCCDDDD
あああいいいうううえええおお
000111222333444

gatsby-config.js の修正

利用するプラグインと data ディレクトリを検索するように指定

module.exports = {
  plugins: [
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: `data`,
        path: `${__dirname}/data/`,
      },
    },
    `gatsby-transformer-remark`,
  ],
}

index.js で file1.md の内容を表示する

markdownRemarkl で html を取得し、表示するだけの index.js を作成

// index.js
import React from "react"
import { graphql } from "gatsby"

export default ({ data }) => {
    const post = data.markdownRemark
    return (
        <div>
            <div dangerouslySetInnerHTML={{ __html: post.html }} />
        </div>
        )
    }

    // 今回はマークダウンが1つなので条件を指定せず、markdownRemarkで取得
    export const query = graphql`
    query {
        markdownRemark {
            html
        }
      }
`

開発サーバを起動し、ブラウザ表示するとマークダウンの内容が表示されます。

gatsby_markdown_1

unsplash コンポーネントを作成し、マークダウン内で使用する

gatsby-config.js の修正

gatsby-transformer-remark のオプションとして gatsby-remark-component を記述します。

module.exports = {
  plugins: [
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: `data`,
        path: `${__dirname}/data/`,
      },
    },
    {
      resolve: "gatsby-transformer-remark",
      options: {
        plugins: [
          {
            resolve: "gatsby-remark-component",
            //変換する要素を指定したいときはoptionに記載する
            // options: { components: ["my-component", "other-component"] }
          }
        ]
      }
    }
  ],
}

コンポーネントの作成

unsplash のランダム画像を表示するコンポーネント Unsplash を作成する。(src\components\Unsplash.js を作成) せっかくなので引数でサイズの指定をできるようにします。

import React from 'react'

const Unsplash = (data) => {
    const url = `https://source.unsplash.com/random/${data.size}`
    return(
        <div>
            <img src={url} />
        </div>
    )
}
export default Unsplash

index.js の変更

index.js には以下の修正を行います。

  1. rehype-react、Unsplash をインポートする
  2. GraphQL の取得内容を html から htmlAst に変更
  3. rehypeReact を使い、unsplash 要素と Unsplash コンポーネントをマッピング
  4. dangerouslySetInnerHTML で表示していた箇所を renderAst に変更
// index.js
import React from "react"
import { graphql } from "gatsby"
// 1. rehype-react、Unsplashをインポートする
import rehypeReact from "rehype-react"
import Unsplash from "../components/Unsplash"


// 3. rehypeReactを使い、unsplash要素とUnsplashコンポーネントをマッピング
const renderAst = new rehypeReact({
    createElement: React.createElement,
    components: { "unsplash": Unsplash},//keyの指定は小文字
  }).Compiler

export default ({ data }) => {
    const post = data.markdownRemark
    return (
        <div>
        {/* 4. dangerouslySetInnerHTMLで表示していた箇所をrenderAstに変更 */}
          {renderAst(post.htmlAst)}
        </div>
        )
    }

    // 2. GraphQLの取得内容をhtmlからhtmlAstに変更
    export const query = graphql`
    query {
        markdownRemark {
            htmlAst
        }
      }
`

マークダウンファイルに unsplash 要素をいれる

マークダウンに<unsplash></unsplash>を記述して、動作を確認する。 <unsplash />は NG。

## マークダウンファイルの内容

AAAABBBBCCCCDDDD
あああいいいうううえええおお
000111222333444

画像の表示
<unsplash size="400x200"></unsplash>


サイズ指定なしの画像の表示
<unsplash></unsplash>

動作確認

開発サーバを起動すると画像の表示が確認できます。

gatsby_markdown_2

gatsby-remark-component を使わない時の警告

gatsby-remark-component を使用すると、コンポーネントを囲っているタグが p から div に変わっている。

gatsby_markdown_3

p タグのままだと裏で警告が出ている。

gatsby_markdown_4

validateDOMNesting(...): <div> cannot appear as a descendant of <p>.

p タグはインライン要素なので、ブロック要素の div タグをネストするのは不適切とのこと。