Gatsby.js で作ったサイトで Amazon リンクを表示する

January 04, 2021

このブログは Gatsby.js で作っていますが、リンクを埋め込みカードのように表示させたいことがあります。 普通の URL は iframely を使って表示させています。

Amazon の場合はあまりよい感じの表示にならない&アフィリエイトIDの埋め込みができないので、Amazon リンクを表示する Component を自作しました。

<Amazon asin="B01EJ7AK5O" />

と ASIN コードを指定してコンポーネントを呼び出すと、こんな感じに表示されます。

環境

  • Gatsby.js v2.28.2

利用する API

商品情報の取得には、Rakuten Rapid API の Amazon Product/Reviews/Keywords を利用しています。 アカウント登録し、あらかじめヘッダーで X-RapidAPI-Key に指定するトークンを取得しておきます。

また、axios を使って API にリクエストを送るのでインストールしておきます。

yarn add axios

コンポーネントの作成

次の内容で components/amazon.js を作成します。 css 情報は別途 gatsby-browser.js で読み込んでいる css に記述しています。

import React, { useEffect, useState } from "react"
import axios from "axios"
import { useStaticQuery, graphql } from "gatsby"

const Amazon = props => {
  const { asin } = props
  const { site } = useStaticQuery(
    graphql`
      query {
        site {
          siteMetadata {
            amazon {
              id
              token
            }
          }
        }
      }
    `
  )
  const { amazon } = site.siteMetadata
  const [data, setData] = useState([])
  const [loading, setLoading] = useState(true)

  useEffect(() => {
    axios({
      method: "GET",
      url:
        "https://amazon-product-reviews-keywords.p.rapidapi.com/product/details",
      headers: {
        "content-type": "application/octet-stream",
        "x-rapidapi-host": "amazon-product-reviews-keywords.p.rapidapi.com",
        "x-rapidapi-key": amazon.token,
        useQueryString: true,
      },
      params: {
        country: "JP",
        asin: asin,
      },
    }).then(resp => {
      setData(resp.data)
      setLoading(false)
    })
  }, [])
  if (loading) {
    return <div />
  }
  const { title, url, main_image, authors, description } = data?.product
  return (
    <div className="blog-amzn-container">
      <div
        className="blog-amzn-wc"
        style={{ backgroundImage: `url(${main_image})` }}
      ></div>
      <div className="blog-amzn-wt">
        <div>
          <strong>
            <a
              href={`${url}/ref=nosim?tag=${amazon.id}`}
              target="_blank"
              rel="noreferrer"
            >
              {title}
            </a>
          </strong>
        </div>
        {authors && <div>{authors[0].author}</div>}
        <div>{description.replace("Read moreRead less", "")}</div>
      </div>
    </div>
  )
}
export default Amazon

クライアントサイドで React のマウント時にのみ API をコールするようにします1useEffect の第2引数に空配列を指定)。

結果が返ってくるまでは(loadingtrue)、内容のない <div> タグを返しておきます。結果を取得したら setData で state に取得結果がセットされるので、取得結果を反映した DOM 要素を返却します。

コンポーネントの定義をマッピングする

MDX ファイル内でコンポーネントを毎回 import するのは面倒なので、 記事を生成するテンプレート(自分の場合は blog-post.js)に <MDXProvider> を使ってあらかじめマッピングしておきます。

import { MDXProvider } from "@mdx-js/react"
import { MDXRenderer } from "gatsby-plugin-mdx"
...
import Amazon from "../components/amazon";
const components = { Amazon };

<MDXProvider components={components}>
  <MDXRenderer>{post.body}</MDXRenderer>
</MDXProvider>

まとめ

ビルド時点で API をコールしたほうが良いかもしれないので、改造するかもです…。

参考資料