I’m building a Next.js application using TypeScript that handles payments with PayPal. I’ve created an input field where the user can enter the amount they want to pay, and I’m using useState to manage this value. However, when the PayPal button is clicked, the createOrder function always receives the initial state value for amount instead of the updated value entered by the user.
Here’s the relevant code:
"use client";
import { useEffect, useState } from 'react';
import { PayPalScriptProvider, PayPalButtons } from "@paypal/react-paypal-js";
import { TextField, Grid, Box } from '@mui/material'; // Importa los componentes de Material-UI
const clientId = process.env.NEXT_PUBLIC_PAYPAL_CLIENT_ID as string;
if (!clientId) {
throw new Error("NEXT_PUBLIC_PAYPAL_CLIENT_ID is not defined in the environment.");
}
const ivaString = process.env.NEXT_PUBLIC_IVA as string;
if (!ivaString) {
throw new Error("NEXT_PUBLIC_IVA is not defined in the environment.");
}
const iva = parseFloat(ivaString);
const initialOptions = {
clientId: clientId,
currency: "EUR",
intent: "capture",
};
export default function Paypal() {
const [state, setState] = useState(0);
const handleAmountChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setState(parseFloat(event.target.value));
};
const createOrder = async (data: any, actions: any) => {
const requestBody = {
amount: state,
tax: (iva * state) / 100,
};
const response = await fetch('/api/paypal/checkout', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(requestBody)
});
if (!response.ok) {
throw new Error('Failed to create order');
}
const responseData = await response.json();
const id = responseData.id;
return id;
};
const onApprove = async (data: any, actions: any) => {
console.log('onApprove', data);
const captureResult = await actions.order.capture();
console.log('Capture Result:', captureResult);
};
const onCancel = (data: any, actions: any) => {
console.log('onCancel', data);
};
return (
<div>
<PayPalScriptProvider options={initialOptions}>
<Grid container spacing={2}>
<Grid item xs={12}>
<TextField
label="Amount"
type="number"
value={state}
onChange={handleAmountChange}
fullWidth
/>
</Grid>
<Grid item xs={12}>
<PayPalButtons
createOrder={createOrder}
onApprove={onApprove}
onCancel={onCancel}
/>
</Grid>
</Grid>
</PayPalScriptProvider>
</div>
);
}
Problem:
The issue I’m facing is that the createOrder function doesn’t seem to be picking up the updated value of state after the user changes the amount in the input field. Instead, it always uses the initial state value, which is 0. The console logs show that state does update correctly when the input changes, but the value in createOrder remains static.
I’ve attempted to debug by checking the createOrder function, and it consistently logs the initial value, not the updated one.
What I Need:
I’m looking for help to ensure that the createOrder function in the PayPal button correctly receives the updated amount from the state after the user inputs a new value.
How can I allow users to enter amount manually with textfield?
Thanks in advance for any advice!
2
Answers
I found that changes are not reflected in the PaypalButtons component props. So a solution is described in this post: Paypal React / Next JS buttons not updating after changing products quantities in cart
Need to use forceReRender props in the PaypalButtons component.
Can you console handleAmountChange function that its correctly getting updated value and update the state.
If its fine. Then we need to check createOrder function, that it should have latest state value. You need make it render somehow using useCallback to get latest updates.