Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug] PaypalButtons Event handlers hold stale state #590

Open
wesbos opened this issue Dec 4, 2024 · 3 comments
Open

[Bug] PaypalButtons Event handlers hold stale state #590

wesbos opened this issue Dec 4, 2024 · 3 comments

Comments

@wesbos
Copy link

wesbos commented Dec 4, 2024

With react-paypal-js ("@paypal/react-paypal-js": "^8.7.0"), the event handlers seem to create a closure and hold old state - its not clear from the docs on how to avoid this, or update.

An example:

function Paypal() {
  const [count, setCount] = useState(0);
  return (
    <>
      <button onClick={() => setCount(count + 1)}>Count: {count}</button>
      <PayPalButtons
        onClick={() => {
          console.log(count) // Always 0
        }}
      />
    </>
  );
}

Click the button a few times, state updates, but when any of the event handlers of PaypalButton are called, it's the stale state.

Seems you are creating a closure of the event handler functions.

This is a problem because people

  1. go to my checkout, enter their info (which updates cart state)
  2. click Paypal as a payment option - this renders the PaypalButtons component
  3. Then they go back to their checkout and change things like coupon, name or email address.
  4. They click the paypal button

So the state is stale back to when the button was initially rendered.

Am I supposed to force a re-render of the button every time my state changes?

I'd consider this a bug as I'd expect the onClick to just use the state, but if it's not a bug, it needs documentation as it doesn't behave as React event handlers do.

@wesbos
Copy link
Author

wesbos commented Dec 4, 2024

Seems I can reload the entire thing like this:

const [{ options }, dispatch] = usePayPalScriptReducer();
// then whenever any state changes
dispatch({ type: 'resetOptions', value: { ...options } });

This can't be the fix though, right?

@wesbos
Copy link
Author

wesbos commented Dec 4, 2024

Apologies for the multiple comments, I see there is also a forceReRender prop for the button, which I assume is like a useEffect dependency

This works, but has the downside of the button flickering and animating any time state of changed.

CleanShot.2024-12-04.at.13.17.11.mp4

And if this happens too quickly (like state is updated on keystroke), these errors appear in the console:

Screenshot 2024-12-04 at 1 25 10 PM

I just want to use state in my onError, onCancel, onApprove, onClick, createOrder methods without having to jump through hoops

@Dandrum
Copy link

Dandrum commented Dec 6, 2024

Hi there,

I'm using nextjs 14.* and have exactly the same problem. It seems that the SDK is not made for SSR because by default every next component is rendered on the server and then hydrated therefore the onFunctions dont get the current state.

The button component needs a 'use client' tag for use in next or a client-only solution.

Do you have the animation problem with the dispatch too, the forceRerender with the animation is not a nice solution.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants