6

I'm currently working on the checkout page of an application where a user can purchase up to three items at one of three prices chosen by the user (this is mostly being done as an experiment). When the user chooses a price by clicking a button this triggers a setState and a new price is stored to the state. When doing console.log I see the new state has been set, but upon checkout it appears the state resets to its initial value. I can't tell why and have no idea where to begin on this one. I imagine on initial render paypal is keeping the initial state it was passed and needs to be rerendered when the new state is set, but not sure how to go about this or even if this is the problem. Any help or guidance is appreciated.

I'm using the @paypal/react-paypal-js library for this paypal implementation, but am welcome to alternative suggestions.

Here is the code I'm using but cut down relevant sections:

import React, {useState, useRef, useEffect} from 'react';
import { PayPalButtons, usePayPalScriptReducer } from "@paypal/react-paypal-js";
import PriceButton from './PriceButton.jsx';
import NumberItemButton from './NumberItemButton';
import {priceOptions, amountItems} from './PriceOptions';



const PaymentPage = () => {
  const [isLoading, setIsLoading] = useState(false);
  const [payAmount, setPayAmount] = useState('5.00');
  const [itemAmount, setItemAmount] = useState('1');

  const payPalOptions = { //Note: This is used in the higher level component PayPalScriptProvider
    "client-id": `${process.env.REACT_APP_PAYPAL_CLIENT_ID}`,
    currency: "USD",
    intent: "capture",
  };

  const createOrder = (data, actions) => { //This will show the initial state when triggered
    return actions.order.create({
      purchase_units : [
        {
          amount: {
            value: payAmount //This stays at the initial State of '5.00' despite the newState being set
          }
        }
      ]
    })
  };

  const onApprove = (data, actions) => {
    return actions.order.capture().then(function(orderData) {
          console.log('Capture result', orderData, JSON.stringify(orderData, null, 2));
          let transaction = orderData.purchase_units[0].payments.captures[0];
          alert('Transaction '+ transaction.status + ': ' + transaction.id + '\n\nSee console for all available details');
    }
  )};

  const onError = (error) => {
    console.log(error)
  }

  console.log(payAmount) //Note: This will show the new State
  return (
    <div>
        <h1>Purchase</h1>
        <label> Choose number of items
        <div>
          {amountItems.map((item, index) => {
            return <NumberItemButton key={index} setItemAmount={setItemAmount} amount={item.amount} />
          })}
        </div>
        </label>
        <label> Pick a price
          <div>
            {priceOptions.map((item, index) => {
              return <PriceButton key={index} itemAmount={itemAmount} setPayAmount={setPayAmount} price={item.price} />
            })}
          </div>
        </label>
        <PayPalButtons
          createOrder={(data, actions) => createOrder(data, actions)}
          onApprove={(data, actions) => onApprove(data, actions)}
          onError={onError}
        />  
    </div>
  );
}


export default PaymentPage;

I'll also add the price button component incase the issue is there

const PriceButton = ({itemAmount, setPayAmount, price}) => { //itemAmount is the amount customer buys, price is the value passed through on the mapping function
  const multPrice = (itemAmount * price).toFixed(2);
  const withTaxPrice = (parseInt(multPrice) + .5).toFixed(2).toString();

  return (
    <button onClick={() => setPayAmount(withTaxPrice)}>${multPrice}</button>
  )
}

export default PriceButton;

Appreciate any help!

4
  • Can you try passing payAmount as a parameter to createOrder? Something like createOrder(data, actions, payAmount) and const createOrder = (data, actions, payAmount) Commented Sep 6, 2021 at 5:48
  • Sadly this did not work. I did find the solution though. Commented Sep 6, 2021 at 16:29
  • Great. Post it so it may help someone else. Commented Sep 6, 2021 at 16:30
  • Sorry I plan to in a few hours. Currently stuck and can't type out a well-written response. Commented Sep 6, 2021 at 21:05

3 Answers 3

14

I came back to this with a fresh pair of eyes and found the solution (though I'm not sure if it's the best one).

The issue is when the Paypal button renders it pulls in the initial state that is passed through, but it needs to be rerendered when a new state is passed.

My solution to this was to pass a forceReRender={[payAmount]} within the PaypalButtons component. This rerenders the Paypal button upon update to the price state and allows me to pass an updated value.

Hope this helps others!

Sign up to request clarification or add additional context in comments.

1 Comment

This should consider as a correct answer
4

I found a better solution. Just use useRef and access the ref.current value!

Comments

2

Use the forceReRender property.

Check out the official Storybook: https://paypal.github.io/react-paypal-js/?path=/docs/example-paypalbuttons--default

<PayPalButtons
    style={style}
    disabled={false}
    forceReRender={[amount, currency, style]} /* <= forceReRender */
    fundingSource={undefined}
    createOrder={(data, actions) => {
        return actions.order
            .create({
                purchase_units: [
                    {
                        amount: {
                            currency_code: currency,
                            value: amount,
                        },
                    },
                ],
            })
            .then((orderId) => {
                // Your code here after create the order
                return orderId;
            });
    }}
    onApprove={function (data, actions) {
        return actions.order.capture().then(function () {
            // Your code here after capture the order
        });
    }}
/>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.