javascriptreactjsreact-hookspaypalpaypal-buttons

useEffect is not updating PayPal client id with axios request


Sometimes it seems the most simpliest stuff is not working. I am doing a GET request to my API to get the paypal_client_id, but it's not updating in time.

import { useState } from 'react';
import axios from 'axios';
import { useEffect } from 'react';

const PayPalButton = ({ total, onPaymentSuccess, onPaymentError, disabled }) => {
  const [paypalClient, setPayPalClient] = useState('test-id');

  useEffect(() => {
    const paypalkey = async () => {
      const { data: clientId } = await axios.get('/api/config/paypal');
      setPayPalClient(clientId);
      console.log(paypalClient);
    };
    paypalkey();
  }, []);
  return (
    <PayPalScriptProvider options={{ 'client-id': paypalClient }}>
      <PayPalButtons
        disabled={disabled}
        forceReRender={[total()]}
        createOrder={(data, actions) => {
          return actions.order.create({
            purchase_units: [
              {
                amount: {
                  value: total(),
                },
              },
            ],
          });
        }}
        onApprove={(data, actions) => {
          return actions.order.capture().then((details) => {
            onPaymentSuccess(data);
          });
        }}
        onError={(err) => {
          onPaymentError();
        }}
      />
    </PayPalScriptProvider>
  );
};

export default PayPalButton;

I thought my useEffect hook would take care to provide the paypal_client_id in time, but it doesn't work.

the API is working, but the request paypal does to authenticate the button is doing it with 'test-id', that proves that my key is not arriving in time.

Any help is much appreciated.


Solution

  • The useEffect triggers at the first render so it's "normal" that the client-id is not there at the "right time".

    You should have a loading in your render to prevent this.

    Like :

        const [paypalClient, setPayPalClient] = useState('');
        
            return (
                {!paypalClient ? <p>Loading...</p> : 
    (<PayPalScriptProvider options={{ 'client-id': paypalClient }}>
                  <PayPalButtons
                    disabled={disabled}
                    forceReRender={[total()]}
                    createOrder={(data, actions) => {
                      return actions.order.create({
                        purchase_units: [
                          {
                            amount: {
                              value: total(),
                            },
                          },
                        ],
                      });
                    }}
                    onApprove={(data, actions) => {
                      return actions.order.capture().then((details) => {
                        onPaymentSuccess(data);
                      });
                    }}
                    onError={(err) => {
                      onPaymentError();
                    }}
                  />
                </PayPalScriptProvider>)}
              );
    

    Or you can simply store your client-id in your environment variables