Stripeを利用することで、決済機能を簡単に実装することができます。
しかし通販機能を実装するためには、決済だけではなく買い物かご(カート)機能も実装する必要があります。
今回は、「use-shopping-cart」を利用して、Reactアプリで簡単にカート機能を実装する方法を紹介します。
use-shopping-cartとは
use-shopping-cartは、Reactでショッピングカート機能を実装するために必要な機能を備えたHookを提供するライブラリです。
内部的にReduxを利用しており、「カート機能」と「Stripe Checkoutへの遷移」の2機能が利用できます。
use-shopping-cartでできること(一部)
use-shopping-cartを利用することで、一般的なショッピングカートを実装するために必要なAPIを簡単に手に入れることができます。
- 商品をカートに追加する
- カートに追加した商品データや合計金額データを取得する
- 商品をカートから削除する
- カート内の商品の個数を変更する
- etc...
use-shopping-cartを使ってカート機能を実装しよう
サンプルアプリのセットアップ
Create React AppやViteを利用してアプリをセットアップしましょう。
// CRA
% npx create-react-app my-app
// Vite
% npm init vite
ライブラリをインストールしよう
useShoppingCartライブラリをインストールします。
この際Stripe.jsも一緒にインストールします。
ただしReact SDKは不要ですのでご注意ください。
% npm install @stripe/stripe-js use-shopping-cart
CartProviderを設定しよう
use-shopping-cartは内部的にReduxを利用しています。
そのため、アプリ全体をCardProvider
の子要素にする必要があります。
import ReactDOM from 'react-dom'
import { CartProvider } from 'use-shopping-cart'
import App from './App'
ReactDOM.render(
<CartProvider
mode="payment"
cartMode="client-only"
stripe={YOUR_STRIPE_API_KEY_GOES_HERE}
successUrl="http://localhost:3000"
cancelUrl="http://localhost:3000"
currency="JPY"
allowedCountries={['US', 'GB', 'JP']}
billingAddressCollection={true}
>
<App />
</CartProvider>,
document.getElementById('root')
)
loadStripe
やredirectToCheckout
などで設定するパラメータをここで設定します。
Providerで設定することで、redirectToCheckout
を呼び出す際にリダイレクトURLなどの情報を省略することができます。
cartModeでStripe Checkoutの起動方法が変更可能です
cartMode
には、checkout-session
とclient-only
の2種類が設定できます。
client-only
を利用した場合は、checkout.sessions.create
APIを利用せずに、クライアント側だけでStripe Checkoutへのリダイレクトを実施します。
APIでCheckoutのセッションを作成したい場合は、checkout-session
を利用しましょう。
商品・料金データを設定しよう
商品データを作成します。簡単な方法はJSONまたはオブジェクトで設定することです。
price_id
とprice
の2つが欠けていると、うまく動作しませんので注意しましょう。
const productData = [
{
name: 'Bananas',
price_id: 'price_xxxx',
price: 400
},
{
name: 'Tangerines',
price_id: 'price_xxxx',
price: 100
}
]
続いて設定した商品データをReactで表示させましょう。
import { formatCurrencyString } from 'use-shopping-cart'
...
<ul>
{productData.map(product => (
<li key={product.price_id}>
{product.name} ({formatCurrencyString({ value: product.price, currency: 'JPY' })}) <br />
<button>
Add 1 to Cart
</button>
</li>
))}
</ul>
formatCurrencyString
を利用することで、金額を指定した通貨に合わせた表示に変換することができます。
カート機能を実装する
いよいよカート機能の実装に入ります。
カートに関するメソッドなどは、useShoppingCart
フックを利用して取得します。
import { useShoppingCart } from 'use-shopping-cart'
...
const { totalPrice, cartCount, addItem, cartDetails, ...args } = useShoppingCart()
カートに商品を追加する機能を実装しよう
まずは表示している商品をカートに追加するボタンを実装しましょう。
import { formatCurrencyString, useShoppingCart } from 'use-shopping-cart'
const Shop = () => {
const {
addItem
} = useShoppingCart()
return (
<div>
<ul>
{productData.map(product => (
<li key={product.price_id}>
{product.name} ({formatCurrencyString({ value: product.price, currency: 'JPY' })}) <br />
<button onClick={() => addItem(product)}>
Add 1 to Cart
</button>
</li>
))}
</ul>
</div>
)
}
button
のonClick
イベントにaddItem
を設定しました。
これで選択した商品をカートに追加完了です。
カートの中身を確認しよう
追加に成功しましたが、実際にカートの中に何が登録されているかがわかりません。
そこでカートの中身についても表示させてみましょう。
const Shop = () => {
const {
addItem,
+ cartDetails,
} = useShoppingCart()
return (
<div>
...
<section>
<h1>Cart</h1>
<ul>
{Object.entries(cartDetails).map(([priceId, cartItem]) => (
<li key={`cart-${priceId}`}>
{cartItem.name} ({cartItem.formattedPrice} * {cartItem.quantity} = {cartItem.formattedValue})<br/>
<button>Increase</button>
<button>Decrease</button>
<button>Cancel</button>
</li>
))}
</ul>
</section>
</div>
)
}
cartDetails
を使用することで、カートに追加された商品データを取得・表示することができます。
# カートの商品数を変更できるようにしよう
カートに追加した商品の数を増減させたり、削除することもできます。
以下のサンプルを参考に、コードを更新しましょう。
const Shop = () => {
const {
addItem,
cartDetails,
+ incrementItem, decrementItem, removeItem,
} = useShoppingCart()
return (
<div>
...
<section>
<h1>Cart</h1>
<ul>
{Object.entries(cartDetails).map(([priceId, cartItem]) => (
<li key={`cart-${priceId}`}>
{cartItem.name} ({cartItem.formattedPrice} * {cartItem.quantity} = {cartItem.formattedValue})<br/>
+ <button onClick={() => incrementItem(priceId)}>1つ増やす</button>
+ <button onClick={() => decrementItem(priceId)}>1つ減らす</button>
+ <button onClick={() => removeItem(priceId)}>削除</button>
</li>
))}
</ul>
</section>
</div>
)
}
これだけでカートの中身を増減や削除できるようになりました。
Stripe Checkoutにリダイレクトさせて、注文できるようにしよう
最後にカートに登録した商品を注文できるようにしましょう。
これもuseShoppingCart
で取得できるメソッドを利用するだけです。
const Shop = () => {
const {
addItem,
cartDetails,
incrementItem, decrementItem, removeItem,
+ redirectToCheckout,
} = useShoppingCart()
return (
<div>
...
+ <button onClick={() => redirectToCheckout()}>
+ 注文する
+ </button>
</div>
)
}
追加した「注文する」ボタンをクリックすると、カートに追加した商品・料金データと個数が反映されたCheckoutページが表示されます。
Appendix: カート情報はどこに保存されている?
実装を見る限り、カートの情報はlocalStorageに保存されています。
そのため、途中でユーザーがサイトから離脱した場合でも、同じブラウザであればカートの内容を維持することができます。
終わりに
use-shopping-cartの基本的な機能について紹介しました。
APIでCheckoutセッションを作成した場合など、ここでは紹介できていないユースケースもまだまだありますので、また改めて紹介したいと思います。
[PR] Stripe開発者向け情報をQiitaにて配信中!
2021年12月よりQiitaにて、Stripe開発者のためのブログ記事更新を開始しました。
- [Stripe Updates]:開発者向けStripeアップデート紹介・解説
- ユースケース別のStripe製品や実装サンプルの紹介
- Stripeと外部サービス・OSSとの連携方法やTipsの紹介
- 初心者向けのチュートリアル(予定)
など、Stripeを利用してオンラインビジネスを始める方法について随時更新してまいります。