我遇到了一个问题,就是做任何状态更改都会重新呈现PayPalHostedFields。如果我将可行的数据输入paypal托管字段,然后进行任何状态更改,组件将重新呈现并清除托管字段。
如何在不每次重新呈现脚本提供程序的情况下对托管字段进行状态管理?
<PayPalScriptProvider options={{
'client-id': process.env.REACT_APP_PAYPAL_CLIENT_ID || 'test',
'data-client-token': token,
components: 'buttons,hosted-fields',
currency: currency
}}>
<PayPalButtons
fundingSource={"paypal"}
style={{ color: "gold", shape: "rect", label: "paypal", height: 40 }}
forceReRender={[price, currency]}
createOrder={createOrder}
onApprove={onApprove}
onCancel={onCancel}
onError={onError}
/>
<div className="paypal-hosted-fields-container-div" style={{display: 'flex', justifyContent: 'space-between', flexWrap: 'wrap'}}>
<PayPalHostedFieldsProvider
styles={{
".valid":{"color":"#28a745"},
".invalid":{"color":"#dc3545"},
"input":{
"font-family":"monospace",
"font-size":"16px"
},
}}
createOrder={createOrder}
onCancel={onCancel}
onError={onError}
>
<div className='ch-pay-radio_div'>
<div
className='ch-pay-radio-shipping-address-first'
onClick={checkCheck}
>
<input
type='radio'
name='ch-radiogroup'
defaultChecked={true}
style={{ marginLeft: '8px', marginTop: '0px' }}
checked={!checked}
/>
<label
className='ch-pay-radio-ship'
style={{ marginBottom: '0px' }}
>
PayPal
</label>
</div>
<div
className='ch-pay-radio-shipping-address'
onClick={checkCheck}
>
<input
type='radio'
name='ch-radiogroup'
defaultChecked={false}
style={{ marginLeft: '8px', marginTop: '0px' }}
checked={checked}
/>
<label
className='ch-pay-radio-ship'
style={{ marginBottom: '0px' }}
>
Card
</label>
</div>
</div>
发布于 2022-02-18 18:00:57
尝试文档示例,使用您自己的凭据,并使用动态token
值和自己的createOrder函数替换获取。
import { useState, useEffect, useRef } from "react";
import {
PayPalScriptProvider,
PayPalHostedFieldsProvider,
PayPalHostedField,
usePayPalHostedFields,
} from "@paypal/react-paypal-js";
const CUSTOM_FIELD_STYLE = {"border":"1px solid #606060","boxShadow":"2px 2px 10px 2px rgba(0,0,0,0.1)"};
const INVALID_COLOR = {
color: "#dc3545",
};
// Example of custom component to handle form submit
const SubmitPayment = ({ customStyle }) => {
const [paying, setPaying] = useState(false);
const cardHolderName = useRef(null);
const hostedField = usePayPalHostedFields();
const handleClick = () => {
if (hostedField) {
if (
Object.values(hostedField.getState().fields).some(
(field) => !field.isValid
) ||
!cardHolderName?.current?.value
) {
return alert(
"The payment form is invalid, please check it before execute the payment"
);
}
setPaying(true);
hostedField
.submit({
cardholderName: cardHolderName?.current?.value,
})
.then((data) => {
// Your logic to capture the transaction
fetch("url_to_capture_transaction", {
method: "post",
})
.then((response) => response.json())
.then((data) => {
// Here use the captured info
})
.catch((err) => {
// Here handle error
})
.finally(() => {
setPaying(false);
});
})
.catch((err) => {
// Here handle error
setPaying(false);
});
}
};
return (
<>
<label title="This represents the full name as shown in the card">
Card Holder Name
<input
id="card-holder"
ref={cardHolderName}
className="card-field"
style={{ ...customStyle, outline: "none" }}
type="text"
placeholder="Full name"
/>
</label>
<button
className={`btn${paying ? "" : " btn-primary"}`}
style={{ float: "right" }}
onClick={handleClick}
>
{paying ? <div className="spinner tiny" /> : "Pay"}
</button>
</>
);
};
export default function App() {
const [clientToken, setClientToken] = useState(null);
useEffect(() => {
(async () => {
const response = await (
await fetch(
"https://braintree-sdk-demo.herokuapp.com/api/paypal/hosted-fields/auth"
)
).json();
setClientToken(response?.client_token || response?.clientToken);
})();
}, []);
return (
<>
{clientToken ? (
<PayPalScriptProvider
options={{
"client-id":
"AdOu-W3GPkrfuTbJNuW9dWVijxvhaXHFIRuKrLDwu14UDwTTHWMFkUwuu9D8I1MAQluERl9cFOd7Mfqe",
components: "buttons,hosted-fields",
"data-client-token": clientToken,
intent: "capture",
vault: false,
}}
>
<PayPalHostedFieldsProvider
styles={{".valid":{"color":"#28a745"},".invalid":{"color":"#dc3545"},"input":{"font-family":"monospace","font-size":"16px"}}}
createOrder={function () {
return fetch(
"your_custom_server_to_create_orders",
{
method: "post",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
purchase_units: [
{
amount: {
value: "2", // Here change the amount if needed
currency_code: "undefined", // Here change the currency if needed
},
},
],
intent: "capture",
}),
}
)
.then((response) => response.json())
.then((order) => {
// Your code here after create the order
return order.id;
})
.catch((err) => {
alert(err);
});
}}
>
<label htmlFor="card-number">
Card Number
<span style={INVALID_COLOR}>*</span>
</label>
<PayPalHostedField
id="card-number"
className="card-field"
style={CUSTOM_FIELD_STYLE}
hostedFieldType="number"
options={{
selector: "#card-number",
placeholder: "4111 1111 1111 1111",
}}
/>
<label htmlFor="cvv">
CVV<span style={INVALID_COLOR}>*</span>
</label>
<PayPalHostedField
id="cvv"
className="card-field"
style={CUSTOM_FIELD_STYLE}
hostedFieldType="cvv"
options={{
selector: "#cvv",
placeholder: "123",
maskInput: true,
}}
/>
<label htmlFor="expiration-date">
Expiration Date
<span style={INVALID_COLOR}>*</span>
</label>
<PayPalHostedField
id="expiration-date"
className="card-field"
style={CUSTOM_FIELD_STYLE}
hostedFieldType="expirationDate"
options={{
selector: "#expiration-date",
placeholder: "MM/YYYY",
}}
/>
<SubmitPayment customStyle={{"border":"1px solid #606060","boxShadow":"2px 2px 10px 2px rgba(0,0,0,0.1)"}} />
</PayPalHostedFieldsProvider>
</PayPalScriptProvider>
) : (
<h1>Loading token...</h1>
)}
</>
);
}
https://stackoverflow.com/questions/71177122
复制相似问题