以前「カート機能を簡単に実装できるフックライブラリ」としてuse-shopping-cartを紹介しました。
今回は、このuse-shopping-cartをNext.jsで作成した静的サイトで利用する方法を紹介します。
事前準備
今回紹介する方法では、REST APIなどを使用せず、クライアント側の組み込みのみでCheckoutのセッションを開始します。
そのため、事前にStripeダッシュボードの設定ページで、「クライアント側のみの組み込み」を有効にしましょう。
直接飛ぶ場合: https://dashboard.stripe.com/settings/checkout
無効化されている状態
Next.jsプロジェクトのセットアップ
まずはNext.jsプロジェクトをセットアップしましょう。
今回はuse-shopping-cart組み込みがメインのため、設定はデフォルトのままにしています。
$ npx create-next-app@latest
npx: 1個のパッケージを1.696秒でインストールしました。
✔ What is your project named? … demo-nextjs-use-shopping-cart
Creating a new Next.js app in /Users/sandbox/demo-nextjs-use-shopping-cart.
セットアップが終わったら、プロジェクトのディレクトリへ移動します。
% cd demo-nextjs-use-shopping-cart
また、環境変数でStripeの公開可能キーとシークレットAPIキーを保存しておきましょう。
env.development
NEXT_PUBLIC_STRIPE_PUBLIC_KEY=pk_test_xxx
STRIPE_SECRET_API_KEY=sk_test_xxx
use-shopping-cartライブラリを追加する
続いてuse-shopping-cartをインストールしましょう。
% npm i use-shopping-cart stripe
use-shopping-cartのProviderを設定する
use-shopping-cartを利用するには、Providerコンポーネントを配置する必要があります。
Next.jsの場合、pages/_app.js
を以下のように変更することで、設定できます。
import '../styles/globals.css'
import type { AppProps } from 'next/app'
+import { CartProvider } from 'use-shopping-cart'
function MyApp({ Component, pageProps }: AppProps) {
- return <Component {...pageProps} />
+ return (
+ <CartProvider
+ mode={"payment"}
+ cartMode={"client-only"}
+ stripe={process.env.NEXT_PUBLIC_STRIPE_PUBLIC_KEY}
+ successUrl={'https://example.com/success'}
+ cancelUrl={'https://example.com/cancel'}
+ currency={'jpy'}
+ >
+ <Component {...pageProps} />
+ </CartProvider>
+ )
}
export default MyApp
これでセットアップは完了です。
use-shopping-cartでサイトを実装する
続いて、useShoppingCartフックを利用して、カート操作や注文のボタンを実装しましょう。
「今すぐ注文」ボタンを作成する
まずは1つの商品をすぐに注文できるボタンを作りましょう。
今すぐ注文ボタンを作るには、checkoutSingleItem
を利用します。
import * as React from "react"
import { useShoppingCart } from 'use-shopping-cart'
const Home = () => {
const { checkoutSingleItem } = useShoppingCart()
return (
<main>
<div>
<button onClick={() => {
checkoutSingleItem('price_xxxx')
}}>今すぐ注文</button>
</div>
</main>
)
export default Home
これで、今すぐ注文
をクリックするとStripeの注文ページにリダイレクトされるようになります。
カート機能を実装する
続いて、商品を追加・変更できるカート機能を作りましょう。
カートに商品を追加する
カートへの追加は、addItem
を利用します。
import * as React from "react"
import { useShoppingCart } from 'use-shopping-cart'
const IndexPage = () => {
const { addItem } = useShoppingCart()
return (
<main>
<div>
<button onClick={() => {
addItem({
name: 'バナナ',
price_id: 'price_xxxxx',
price: 400
})
}}>バナナを追加する</button>
<button onClick={() => {
addItem({
name: 'パン',
price_id: 'price_xxxxx',
price: 400
})
}}>パンを追加する</button>
</div>
</main>
)
export default IndexPage
これで、use-shopping-cart内部にあるstoreに商品のデータを追加できるようになりm最多。
カートの中身を表示する
追加したカートの中身をみるには、cartDetails
を利用します。
また、formattedTotalPrice
を利用することで、合計金額も取得できます。
import * as React from "react"
import { useShoppingCart } from 'use-shopping-cart'
const IndexPage = () => {
const { formattedTotalPrice, cartDetails } = useShoppingCart()
return (
<main>
<div>
<ul>
{Object.values(cartDetails).map((cart: any) => {
return (
<li key={cart.id}>
{cart.name} - {cart.formattedPrice} * {cart.quantity} = {cart.formattedValue}
</li>
)
})}
<li>合計: {formattedTotalPrice}</li>
</ul>
</div>
</main>
)
export default IndexPage
これで、カートの中身をユーザーに表示できるようになりました。
カートの商品数を変更できるようにする
カートの数量を変更する関数もフックに用意されています。
import * as React from "react"
import { useShoppingCart } from 'use-shopping-cart'
const IndexPage = () => {
- const { formattedTotalPrice, cartDetails } = useShoppingCart()
+ const { formattedTotalPrice, cartDetails, decrementItem, incrementItem, removeItem } = useShoppingCart()
return (
<main>
<div>
<ul>
{Object.values(cartDetails).map((cart: any) => {
return (
<li key={cart.id}>
{cart.name} - {cart.formattedPrice} * {cart.quantity} = {cart.formattedValue}
+ <button onClick={() => decrementItem(cart.price_id)}>1つ減らす</button>
+ <button onClick={() => incrementItem(cart.price_id)}>1つ増やす</button>
+ <button onClick={() => removeItem(cart.price_id)}>削除</button>
</li>
)
})}
<li>合計: {formattedTotalPrice}</li>
</ul>
</div>
</main>
)
export default IndexPage
これらを組み合わせることで、とても簡素ですが通販に欠かせないカートシステムを実装できました。
注文ページ(Stripe Checkout)へ移動する
最後にStripe Checkoutへのリダイレクトするボタンを追加しましょう。
注文ページへのリンクはredirectToCheckout
を利用します。
import * as React from "react"
import { useShoppingCart } from 'use-shopping-cart'
const IndexPage = () => {
- const { formattedTotalPrice, cartDetails, decrementItem, incrementItem, removeItem } = useShoppingCart()
+ const { formattedTotalPrice, cartDetails, decrementItem, incrementItem, removeItem, redirectToCheckout } = useShoppingCart()
return (
<main>
<div>
<ul>
{Object.values(cartDetails).map((cart: any) => {
return (
<li key={cart.id}>
{cart.name} - {cart.formattedPrice} * {cart.quantity} = {cart.formattedValue}
+ <button onClick={() => decrementItem(cart.price_id)}>1つ減らす</button>
+ <button onClick={() => incrementItem(cart.price_id)}>1つ増やす</button>
+ <button onClick={() => removeItem(cart.price_id)}>削除</button>
</li>
)
})}
<li>合計: {formattedTotalPrice}</li>
</ul>
<button onClick={() => redirectToCheckout()}>注文する</button>
</div>
</main>
)
export default IndexPage
カート内の商品情報などは、use-shopping-cart側が内部的に処理してくれるため、とてもシンプルな実装で対応できます。
Next.jsでStripeの料金データを取り込む
ここまでは、料金・商品データをベタ打ちしていました。
Next.jsのSSGモードでサイトを構築している場合、getStaticProps
関数内でStripe APIを呼び出すことで、料金データを自動で取り込みできるようになります。
import Stripe from 'stripe'
export const getStaticProps = async () => {
const stripe = new Stripe(process.env.STRIPE_SECRET_API_KEY, {
apiVersion: '2020-08-27'
})
const prices = await stripe.prices.list()
return {
props: {
prices
}
}
}
また、use-shopping-cartのaddItem
で使える形にするには、以下のような整形を行いましょう。
export const getStaticProps = async () => {
const stripe = new Stripe(process.env.STRIPE_SECRET_API_KEY, {
apiVersion: '2020-08-27'
})
const prices = await stripe.prices.list()
return {
props: {
- prices
+ prices: prices.data.map(price => {
+ if (!price.active) return null;
+ return {
+ price_id: price.id,
+ name: price.nickname,
+ price: price.unit_amount,
+ currency: price.currency,
+ }
+ })
}
}
}
ビルド時の注意
next build
を実行する場合、環境変数を.env.local
や.env.development
のみの保存しているとエラーになります。
Error: You did not provide an API key. You need to provide your API key in the Authorization header, using Bearer auth (e.g. 'Authorization: Bearer YOUR_SECRET_KEY'). See https://stripe.com/docs/api#authentication for details, or we can help at https://support.stripe.com/.
これは、ビルド時に読まれる環境変数ファイルが異なるためですので、Next.jsのドキュメントを参考にファイルを配置するようにしましょう。
終わりに
サーバー側の処理でCheckoutセッションを開始していないため、機能に制限があることに注意が必要です。
ですが、Next.jsのSSGモードのみで完結するサイトにEC機能を組み込みたい場合、use-shopping-cartとの組み合わせがとても便利です。
Stripeを使ったオンライン決済の第一歩として、ぜひお試しください。
[PR] Stripe開発者向け情報をQiitaにて配信中!
- [Stripe Updates]:開発者向けStripeアップデート紹介・解説
- ユースケース別のStripe製品や実装サンプルの紹介
- Stripeと外部サービス・OSSとの連携方法やTipsの紹介
- 初心者向けのチュートリアル(予定)
など、Stripeを利用してオンラインビジネスを始める方法について週に2〜3本ペースで更新中です。