Next.js App RouterでStripe Elementを使う場合は、`loadStripe`はクライアントコンポーネントで実行する
タイトルの通り、Stripe ElementのJSファイルを使ったデモアプリ作成時のハマりをメモ。loadStripe関数の返り値がPromise<null>になり、決済フォームが表示されない問題を解決。解決策は、’use client’を設定しているコンポーネントでloadStripeを実行すること。詳細は参考リンクに記載。
広告ここから
広告ここまで
目次
タイトルの通りです。デモアプリ作成時にハマったのでメモとして記録します。
動かなかったケース
app/payment/page.tsx
のようなファイルを作成し、その中でStripe Element側のJSファイルも記述しました。
const stripePromise = loadStripe('pk_test_xxx');
const stripe = new Stripe('sk_test_xxx', {
apiVersion: '2023-10-16'
})
export default async function InstallmentPayment() {
const paymentIntent = await stripe.paymentIntents.create({
amount: 3099,
currency: 'mxn',
})
return (
<main className="flex min-h-screen flex-col items-center justify-between p-24">
<div className="mb-32 ">
<h1 className='text-4xl text-center font-extrabold'>Installment</h1>
<CheckoutForm
stripe={stripePromise}
paymentIntent={{
client_secret: paymentIntent.client_secret,
payment_method_options: paymentIntent.payment_method_options
}}
/>
</div>
</main>
)
}
クライアントコンポーネントはこのような形です。
export const CheckoutForm:FC<{
stripe: ReturnType<typeof loadStripe>;
paymentIntent: Pick<Stripe.PaymentIntent, 'client_secret' | 'payment_method_options'>;
}> = ({
stripe,
paymentIntent,
}) => {
if (!paymentIntent.client_secret) return null;
return (
<>
<Elements stripe={stripe} options={{
clientSecret: paymentIntent.client_secret
}}>
<PaymentElement />
</Elements>
</>
)
}
この方法では、loadStripe
の戻り値が常にPromise<null>
になる様子で、Payment IntentのClient Secretをいくら渡しても決済フォームが表示されません。
loadStripe
はクライアントコンポーネントで
解決方法はとてもシンプルで、'use client'
を設定しているコンポーネントでloadStripe
を実行します。
const stripePromise = loadStripe('pk_test_xxx');
export const CheckoutForm:FC<{
paymentIntent: Pick<Stripe.PaymentIntent, 'client_secret' | 'payment_method_options'>;
}> = ({
paymentIntent,
}) => {
if (!paymentIntent.client_secret) return null;
return (
<>
<Elements stripe={stripePromise} options={{
clientSecret: paymentIntent.client_secret
}}>
<PaymentElement />
</Elements>
</>
)
}