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

Blog

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

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

<Amazon asin="B01EJ7AK5O" />

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

<Amzn asin="B01EJ7AK5O" />

動作を確認した環境

  • Gatsby.js v2.28.2

利用するAPI

商品情報の取得には、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をコールするようにします[^1](useEffectの第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>

参考資料