stripe / react-stripe-js

React components for Stripe.js and Stripe Elements
https://stripe.com/docs/stripe-js/react
MIT License
1.78k stars 272 forks source link

update "amount" for <PaymentRequestButtonElement /> #65

Closed brunocrosier closed 4 years ago

brunocrosier commented 4 years ago

I'm trying to make the "amount" update based on state change.

However, despite the state's value changing correctly, the Payment Request's "amount" remains at the initial value.

Please check out this codesandbox for a reproduction / code. It is a forked version of the offical example, with a simple button that updates the react state called "amount".

To see what I mean on the frontend, you can check: https://oushf.csb.app/payment-request-button-element

Any ideas how to make this work? There are no docs about this on stripe.com and I think this is an extremely common use case..

Thanks!

brunocrosier commented 4 years ago

Managed to answer my own question :)

I've updated the Codesandbox with the solution

Essentially you need to run paymentRequest.update inside of useEffect every time your amount changes. What tripped me up was that the amount must be a Number as opposed to a String, or it will crash the page.

It will look something like this:

useEffect(() => {
    if (paymentRequest && amount) {
      paymentRequest.update({
        total: {
          label: "Demo total",
          amount: Number(amount)
        }
      });
    }
  }, [paymentRequest, amount]);
brunocrosier commented 4 years ago

I do think you should add an example for this though!

kimmikirino commented 3 years ago

@brunocrosier I tried to use useEffect but for some reason it just updates at the first time, when I change the amount again it is not updating anymore, can u sahre ur sandbox again pls?

brunocrosier commented 3 years ago

@brunocrosier I tried to use useEffect but for some reason it just updates at the first time, when I change the amount again it is not updating anymore, can u sahre ur sandbox again pls?

Hey, sorry - it's been so long that I don't really remember this :) Could you post a reproduction and I'll have a little look?

From the sounds of it, if it's only updating the first time, then I would guess that it's because you don't have the correct dependencies in your useEffect.

Here is the relevant code in the docs: https://stripe.com/docs/stripe-js/elements/payment-request-button?html-or-react=react#react-create-payment-request-instance

kimmikirino commented 3 years ago

@brunocrosier I tried to use useEffect but for some reason it just updates at the first time, when I change the amount again it is not updating anymore, can u sahre ur sandbox again pls?

Hey, sorry - it's been so long that I don't really remember this :) Could you post a reproduction and I'll have a little look?

From the sounds of it, if it's only updating the first time, then I would guess that it's because you don't have the correct dependencies in your useEffect.

Here is the relevant code in the docs: https://stripe.com/docs/stripe-js/elements/payment-request-button?html-or-react=react#react-create-payment-request-instance

I actually did exactly what the docs says, but adding some code to update the amount like u did.

useEffect(() => {
    if (paymentRequest && amount) {
      paymentRequest.update({
        total: {
          label: "Demo total",
          amount: Number(amount)
        }
      });
    }
  }, [paymentRequest, amount]);

but when I change the amount it just update once, if I change the amount again, for some reason it doenst update anymore.

TuliantsevViktor commented 2 years ago

@brunocrosier I tried to use useEffect but for some reason it just updates at the first time, when I change the amount again it is not updating anymore, can u sahre ur sandbox again pls?

Hey, sorry - it's been so long that I don't really remember this :) Could you post a reproduction and I'll have a little look? From the sounds of it, if it's only updating the first time, then I would guess that it's because you don't have the correct dependencies in your useEffect. Here is the relevant code in the docs: https://stripe.com/docs/stripe-js/elements/payment-request-button?html-or-react=react#react-create-payment-request-instance

I actually did exactly what the docs says, but adding some code to update the amount like u did.

useEffect(() => {
    if (paymentRequest && amount) {
      paymentRequest.update({
        total: {
          label: "Demo total",
          amount: Number(amount)
        }
      });
    }
  }, [paymentRequest, amount]);

but when I change the amount it just update once, if I change the amount again, for some reason it doenst update anymore.

I have the same issue( Did you manage to solve somehow ? And also I believe all is fine with useeffect deps cause effect fires on amount change, but payment Request changes only once

thiagotsn commented 1 year ago

If anybody is still looking for a fix on updating only once:

We need to avoid creating a new paymentRequest if already exists. So in the init:

  useEffect(() => {
    if (stripe && amount && !paymentRequest) {
      const pr = stripe.paymentRequest({
        country: 'US',
        currency: 'usd',
        requestPayerEmail: false,
        requestPayerName: false,
        total: {
          amount: Number(amount),
          label: "Demo total", 
        },
      });

      // Check the availability of the Payment Request API.
      pr.canMakePayment().then((result) => {
        if (result) {
          setPaymentRequest(pr);
        }
      });
    }
  }, [stripe, amount, paymentRequest]);

Then updating:

useEffect(() => {
    if (paymentRequest && amount) {
      paymentRequest.update({
        total: {
          label: "Demo total",
          amount: Number(amount)
        }
      });
    }
  }, [paymentRequest, amount]);
AleksaButterfly commented 1 year ago

It's also possible to add unique ID to the wrapper component that will force re-render every time the key changes.

creaturechris commented 5 months ago

Bump @brunocrosier's answer. (Thanks)

NOTE: you must include the label. Just updating the amount causes an error even if the label stays the same.