React 集成
在 React 应用程序中集成 Access Checkout Web SDK。
集成
您必须将 SDK
checkout.js
脚本添加到应用程序 html 代码中,并确保仅执行一次。 为此,您要将脚本添加到主应用程序中,或作为其中一个组件的一部分,动态添加。在初始化 SDK 之前,您必须成功加载
checkout.js
脚本。 因为该脚本在window
对象上创建了一个初始化机制所必需的对象。在组件卸载阶段,且在 DOM 仍然可用的情况下,您只能调用一次 SDK 的
remove()
方法。 通过使用useLayoutEffect
钩子和调用由此钩子运行的 cleanup 函数中的remove()
方法,可执行此操作。
完整集成示例
Copied!
import React, {useEffect, useLayoutEffect} from "react";
import "./CheckoutIntegrationSample.css";
function scriptAlreadyLoaded(src) {
return document.querySelector(`script[src="${src}"]`);
}
function loadCheckoutScript(src) {
return new Promise((resolve, reject) => {
if (scriptAlreadyLoaded(src)) {
resolve();
return;
}
let checkoutScript = document.createElement("script");
checkoutScript.src = src;
checkoutScript.onload = resolve;
checkoutScript.onerror = reject;
document.head.appendChild(checkoutScript);
});
}
function addWorldpayCheckoutToPage() {
return new Promise((resolve, reject) => {
(function () {
window.Worldpay.checkout.init(
{
id: "identity",
form: "#container",
fields: {
pan: {
selector: "#card-pan",
},
expiry: {
selector: "#card-expiry",
},
cvv: {
selector: "#card-cvv",
},
},
styles: {
"input.is-valid": {
"color": "green",
},
"input.is-invalid": {
"color": "red",
},
"input.is-onfocus": {
"color": "black",
},
},
enablePanFormatting: true,
},
function (error, checkout) {
if (error) {
reject(error);
} else {
resolve(checkout);
}
},
);
})();
});
}
function CheckoutIntegrationSample() {
const checkoutScriptUrl = "https://try.access.worldpay.com/access-checkout/v1/checkout.js";
let checkout;
function generateSession () {
checkout.generateSessionState(
function (error, session) {
if (error) {
console.warn(`Failed to generate session: ${error}`);
return;
}
const infoDiv = document.querySelector(".info");
infoDiv.innerHTML += `<div>Session retrieved is ${session}</div>`;
});
}
function clearForm () {
checkout.clearForm(() => {
document.querySelector(".info").innerHTML = "";
});
}
useEffect(() => {
loadCheckoutScript(checkoutScriptUrl)
.then(() => {
addWorldpayCheckoutToPage()
.then((checkoutInstance) => {
checkout = checkoutInstance;
})
.catch(console.warn);
})
.catch(console.warn);
}, []);
useLayoutEffect(() => {
// Make sure to call the remove method (once) in order to deallocate the SDK from memory
return () => checkout.remove();
},
[]);
return (
<section className="container" id="container">
<section className="card">
<section id="card-pan" className="field" />
<section className="columns">
<section>
<section id="card-expiry" className="field" />
</section>
<section>
<section id="card-cvv" className="field" />
</section>
</section>
<section className="buttons">
<button className="submit" type="button" onClick={generateSession}>
Generate Session
</button>
<button className="clear" type="button" onClick={clearForm}>
Clear
</button>
</section>
</section>
<div id="info" className="info" />
</section>
);
}
export default CheckoutIntegrationSample;
import React, {useEffect, useLayoutEffect} from "react"; import "./CheckoutIntegrationSample.css"; function scriptAlreadyLoaded(src) { return document.querySelector(`script[src="${src}"]`); } function loadCheckoutScript(src) { return new Promise((resolve, reject) => { if (scriptAlreadyLoaded(src)) { resolve(); return; } let checkoutScript = document.createElement("script"); checkoutScript.src = src; checkoutScript.onload = resolve; checkoutScript.onerror = reject; document.head.appendChild(checkoutScript); }); } function addWorldpayCheckoutToPage() { return new Promise((resolve, reject) => { (function () { window.Worldpay.checkout.init( { id: "identity", form: "#container", fields: { pan: { selector: "#card-pan", }, expiry: { selector: "#card-expiry", }, cvv: { selector: "#card-cvv", }, }, styles: { "input.is-valid": { "color": "green", }, "input.is-invalid": { "color": "red", }, "input.is-onfocus": { "color": "black", }, }, enablePanFormatting: true, }, function (error, checkout) { if (error) { reject(error); } else { resolve(checkout); } }, ); })(); }); } function CheckoutIntegrationSample() { const checkoutScriptUrl = "https://try.access.worldpay.com/access-checkout/v1/checkout.js"; let checkout; function generateSession () { checkout.generateSessionState( function (error, session) { if (error) { console.warn(`Failed to generate session: ${error}`); return; } const infoDiv = document.querySelector(".info"); infoDiv.innerHTML += `<div>Session retrieved is ${session}</div>`; }); } function clearForm () { checkout.clearForm(() => { document.querySelector(".info").innerHTML = ""; }); } useEffect(() => { loadCheckoutScript(checkoutScriptUrl) .then(() => { addWorldpayCheckoutToPage() .then((checkoutInstance) => { checkout = checkoutInstance; }) .catch(console.warn); }) .catch(console.warn); }, []); useLayoutEffect(() => { // Make sure to call the remove method (once) in order to deallocate the SDK from memory return () => checkout.remove(); }, []); return ( <section className="container" id="container"> <section className="card"> <section id="card-pan" className="field" /> <section className="columns"> <section> <section id="card-expiry" className="field" /> </section> <section> <section id="card-cvv" className="field" /> </section> </section> <section className="buttons"> <button className="submit" type="button" onClick={generateSession}> Generate Session </button> <button className="clear" type="button" onClick={clearForm}> Clear </button> </section> </section> <div id="info" className="info" /> </section> ); } export default CheckoutIntegrationSample;
.container {
display: flex;
align-items: center;
flex-direction: column;
}
.card {
background: white;
padding: 20px 30px;
top: -30px;
width: 100%;
max-width: 300px;
border-radius: 12px;
box-shadow: 3px 3px 60px 0px rgba(0, 0, 0, 0.1);
}
.columns {
display: flex;
}
.columns > * {
margin-right: 15px;
}
.field {
height: 40px;
border-bottom: 1px solid lightgray;
}
.field.is-onfocus {
border-color: black;
}
.field.is-empty {
border-color: orange;
}
.field.is-invalid {
border-color: red;
}
.field.is-valid {
border-color: green;
}
#card-pan {
margin-bottom: 30px;
}
.submit {
background: green;
cursor: pointer;
width: 200px;
margin-top:30px;
color: white;
outline: 0;
font-size: 14px;
border: 0;
border-radius: 30px;
text-transform: uppercase;
font-weight: bold;
padding: 15px 0;
transition: background 0.3s ease;
margin-right:20px;
}
.clear {
background: green;
cursor: pointer;
width: 100px;
margin-top:30px;
color: white;
outline: 0;
font-size: 14px;
border: 0;
border-radius: 30px;
text-transform: uppercase;
font-weight: bold;
padding: 15px 0;
transition: background 0.3s ease;
}
.buttons {
display: flex;
}
.info {
width: 600px;
word-wrap:break-word;
margin-top: 20px;
color: green;
}
.container { display: flex; align-items: center; flex-direction: column; } .card { background: white; padding: 20px 30px; top: -30px; width: 100%; max-width: 300px; border-radius: 12px; box-shadow: 3px 3px 60px 0px rgba(0, 0, 0, 0.1); } .columns { display: flex; } .columns > * { margin-right: 15px; } .field { height: 40px; border-bottom: 1px solid lightgray; } .field.is-onfocus { border-color: black; } .field.is-empty { border-color: orange; } .field.is-invalid { border-color: red; } .field.is-valid { border-color: green; } #card-pan { margin-bottom: 30px; } .submit { background: green; cursor: pointer; width: 200px; margin-top:30px; color: white; outline: 0; font-size: 14px; border: 0; border-radius: 30px; text-transform: uppercase; font-weight: bold; padding: 15px 0; transition: background 0.3s ease; margin-right:20px; } .clear { background: green; cursor: pointer; width: 100px; margin-top:30px; color: white; outline: 0; font-size: 14px; border: 0; border-radius: 30px; text-transform: uppercase; font-weight: bold; padding: 15px 0; transition: background 0.3s ease; } .buttons { display: flex; } .info { width: 600px; word-wrap:break-word; margin-top: 20px; color: green; }