我在Medusa-JS Next JS前端设置Stripe payment时遇到了一些问题。
当在checkoutForm
中输入卡片详细信息时,当点击我的表单内的任何东西而不是PaymentElement
时,整个StripePayment
都会重新渲染。
我怀疑这是由于我的条纹组件的使用效果的变化,但我不明白为什么它应该在我的表单内更新。
我的代码StripePayment - component
"use client";
import { useState, useEffect } from "react";
import { loadStripe } from "@stripe/stripe-js";
import { Elements } from "@stripe/react-stripe-js";
import CheckoutForm from "./form";
const STRIPE_PK_KEY = process.env.NEXT_PUBLIC_STRIPE_PK_KEY;
const StripePayment = ({ cart }) => {
const [stripePromise, setStripePromise] = useState(null);
const [clientSecret, setClientSecret] = useState();
useEffect(() => {
if (!STRIPE_PK_KEY && !cart && !cart.payment_sessions) {
return null;
}
const isStripeAvailable = cart.payment_sessions?.some(
(session) => session.provider_id === "stripe"
);
if (!isStripeAvailable) {
return;
}
setStripePromise(loadStripe(STRIPE_PK_KEY));
setClientSecret(cart.payment_session.data.client_secret);
}, [cart.id]);
return (
<div>
<h1>Stripe payment</h1>
{stripePromise && clientSecret && (
<Elements stripe={stripePromise} options={{ clientSecret }}>
<CheckoutForm clientSecret={clientSecret} cart={cart} />
</Elements>
)}
</div>
);
};
export default StripePayment;
CheckoutForm - component
"use client";
import {
useElements,
useStripe,
PaymentElement,
} from "@stripe/react-stripe-js";
import { useState } from "react";
import medusaClient from "../../../lib/medusaClient";
export default function Form({ clientSecret, cart }) {
const stripe = useStripe();
const elements = useElements();
const [message, setMessage] = useState("");
const [isProcessing, setIsProcessing] = useState(false);
const handleSubmit = async (e) => {
e.preventDefault();
if (!stripe || !elements) {
console.log("No tripe or elements");
return;
}
setIsProcessing(true);
const { error, paymentIntent } = await stripe.confirmCardPayment(
clientSecret,
{
payment_method: {
card: elements.getElement(PaymentElement),
billing_details: {
name: e.target.name.value,
email: e.target.email.value,
phone: e.target.phone.value,
address: {
city: cart.shipping_address.city,
country: cart.shipping_address.country,
line1: cart.shipping_address.line1,
line2: cart.shipping_address.line2,
postal_code: cart.shipping_address.postal_code,
},
},
},
}
);
if (error) {
setMessage(error.message);
} else if (paymentIntent && paymentIntent.status === "succeeded") {
setMessage("Payment succeeded");
try {
await medusaClient.carts.complete(cart.id);
console.log("Order completed");
} catch (err) {
console.error("Error completing order:", err);
}
} else {
setMessage("An unexpected error occurred");
}
console.log("Message: ", message);
setIsProcessing(false);
};
return (
<form id="payment-form" onSubmit={(e) => handleSubmit(e)}>
{/* INPUT LABELS OMITTED FOR SAKE OF READIBILITY */}
<PaymentElement id="payment-element" />
<button
className="px-4 py-2 mt-4 text-white bg-blue-500"
disabled={isProcessing || !stripe || !elements}
id="submit"
>
<span id="button-text">
{isProcessing ? "Processing ... " : "Pay now"}
</span>
</button>
{/* Show any error or success messages */}
{message && <div id="payment-message">{message}</div>}
</form>
);
}
我看到你的代码中有一些不寻常的东西:
- 你正在使用
confirmCardPayment
,这是用于当你使用carelement,如果你使用<PaymentElement>
你必须使用confirmPayment
代替 - 与此相关,我不明白为什么你把clientSecret传递给CheckoutForm组件;因为你不需要它——你只需要使用
useElements()
,它提供了已经初始化并知道clientSecret的全局Stripe实例。也许这个额外的依赖会导致一些重渲染问题?
正常的集成更像这样:
Elements stripe={stripePromise} options={{ clientSecret }}>
<CheckoutForm cart={cart} />
</Elements>
CheckoutForm:
...
const { error } = await stripe.confirmPayment({
elements, // from useElements ; you do not need to pass the clientSecret
confirmParams: {
// Make sure to change this to your payment completion page
return_url: `${window.location.origin}/completion`,
payment_method_data: {
billing_details:{
name: e.target.name.value,
email: e.target.email.value,
...
}
}
},
});
...
https://github.com/stripe-samples/accept-a-payment/tree/504ffe70e4ac54a21c2c8ce3b5c426c12df6f351/payment-element/client/react-cra/src
https://stripe.com/docs/payments/accept-a-payment?platform=web& ui = elements&客户= #反应web-collect-payment-details
我会尝试重写你的代码以匹配Stripe的文档,看看这是否有影响。