Skip to main content

[Stripe] stripe with React

install package

npm i @stripe/react-stripe-js @stripe/stripe-js

到 stripe 官網新增帳戶拿到 public key,設置在.env 裡面

REACT_APP_STRIPE_PUBLISHABLE_KEY="............"

進到.gitignore,設置.env 不將其推上去。 在 utils/stripe/stripe.utils.js,使用loadStripe帶入 public key 取得 promise

utils/stripe/stripe.utils.js
import { loadStripe } from "@stripe/stripe-js";

export const stripePromise = loadStripe(
process.env.REACT_APP_STRIPE_PUBLISHABLE_KEY
);

像是 context 的 provider 一樣,匯入 Elements 包裹住要使用到 stripe 的元件,裡面的 props 帶入stripe={stripePromise}

index.js
import { Elements } from "@stripe/react-stripe-js";
import { stripePromise } from "./utils/stripe/stripe.utils";

<Elements stripe={stripePromise}>
<App />
</Elements>;

接著,是後端的操作,因為我們沒有架設後端,使用 netlify 作為我們的雲端伺服器,我們透過 serverless function 來完成 stripe 的接受付費。

首先,先下載 stripe 的 node module

npm i stripe // stripe node.js library

https://github.com/stripe/stripe-node

到.env 設置 secret key,secret key 放在後端,不能給任何人知道!

STRIPE_SECRET_KEY="......"
netlify/functions/create-payment-intent.js
require("dotenv").config(); // 取得.env變數
const stripe = require("stripe")(process.env.STRIPE_SECRET_KEY); // 帶入 secret key

製作一個 API 的連接點,並建立付費物件,如果成功則回傳 status code(200)和付費物件,失敗則回傳 status code(400)和錯誤訊息。

exports.handler = async (event) => {
try {
const { amount } = JSON.parse(event.body); // 解析event.body並取得amount

const paymentIntent = await stripe.paymentIntents.create({
amount,
currency: "usd",
payment_method_types: ["card"],
});

return {
statusCode: 200,
body: JSON.stringify({ paymentIntent }), // 回傳paymentIntent的JSON
};
} catch (err) {
console.log({ err });

return {
status: 400,
body: JSON.stringify({ err }),
};
}
};

有了這個 serverless function,透過fetch的方式傳交易資料給後端,並將上述動作存成一個函式,供我們在提交表單時(onSubmit),帶入資料並呼叫函式(paymentHandler)。

payment-form.component.jsx
import { CardElement, useStripe, useElements } from "@stripe/react-stripe-js";

const PaymentForm = () => {
const stripe = useStripe();
const elements = useElements();

const paymentHandler = async (e) => {
e.preventDefault();

if (!stripe || !elements) {
return;
} // 檢查Stripe.js是否匯入完成以及確保能使用stripe.confirmPayment的方法

const response = await fetch("/.netlify/functions/create-payment-intent", {
method: "post",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ amount: 10000 }), // 先使用給定的數值
}).then((res) => res.json());

const {
paymentIntent: { client_secret },
} = response; // 從回傳的交易資料取得client_secret

const paymentResult = await stripe.confirmCardPayment(client_secret, {
payment_method: {
card: elements.getElement(CardElement),
billing_details: {
name: "Steven Wang",
},
},
});

if (paymentResult.error) {
alert(paymentResult.error);
} else {
if (paymentResult.paymentIntent.status === "succeeded") {
alert("Payment Successful");
}
}
};

return (
<PaymentFormContainer>
<h2>Credit Card Payment: </h2>
<FormContainer onSubmit={paymentHandler}>
<CardElement />
<Button buttonType={BUTTON_TYPE_CLASSES.inverted}>Pay now</Button>
</FormContainer>
</PaymentFormContainer>
);
};

stripe elements: https://stripe.com/docs/stripe-js/react#available-element-components

測試的卡號可以參考Stripe Test Cards,可以 424242...打下去。