Gatsby.js で作ったサイトで Amazon リンクを表示する
このブログは 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 引数に空配列を指定)。
結果が返ってくるまでは(loading
が true
)、内容のない <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>