react-stripe-js icon indicating copy to clipboard operation
react-stripe-js copied to clipboard

[BUG]: Elements not rendering at all after client-side navigation in Next.js

Open vincentleeuwen opened this issue 2 years ago • 1 comments

What happened?

TLDR: Stripe Elements is not rendering anything when using client side routing to checkout and gives no errors or clues what is wrong.

I'm trying to do something that I would imagine is a pretty standard use case in Next.js, but somehow I can't make it work. The elements are rendering fine when I hit refresh, but after a client side refresh they simply don't render at all.

Any idea what I'm doing wrong?

I have the following:

pages/checkout/pay.js

import stripe from 'stripe';

import Pay from '@components/Checkout/Pay';

const stripeApi = stripe(process.env.STRIPE_SECRET_API_KEY);

export async function getServerSideProps() {
  const amount = 1000;

  const stripeData = await stripeApi.paymentIntents.create({
    amount,
    currency: 'eur',
    automatic_payment_methods: { enabled: true },
  });

  return {
    props: {
      stripeSecret: stripeData.client_secret,
    },
  };
}

export default Pay;

/components/Pay.js:

const ElementsPay = ({ stripeSecret }) => {
  const options = {
    clientSecret: stripeSecret,
  };

  return (
    <Elements stripe={stripePromise} options={options}>
      <Pay />
    </Elements>
  );
};

const Pay = () => {
  return (
    <div style={{ height: 500 }}>
      <h1>Why no elements rendered?</h1>
      <PaymentElement />
    </div>
  );
};

Then on /pages/index.js, I put:

import { useRouter } from 'next/router';

const App = () => {
  const router = useRouter();

  const goToCheckout = () => {
    router.push(
      '/pay',
    );
  };

  return (
    <button onClick={goToCheckout}>Go to checkout</button>
  )
}

When I use the button, I see the following:

Only after a refresh, the stripe elements form wil load, but on a client side navigation it always fails with no error message whatsoever.

Client side nav:

Screenshot 2022-08-14 at 12 23 11

After refresh:

Screenshot 2022-08-14 at 12 23 20

Environment

No response

Reproduction

No response

vincentleeuwen avatar Aug 14 '22 10:08 vincentleeuwen

I'm unsure if you're on the latest version (1.10 at the time of writing), but this problem was solved for me by updating to the latest version. I believe it was caused by a previous version using useLayoutEffect which does not play nice with Next.js

daneburns avatar Aug 16 '22 17:08 daneburns

@daneburns Thanks for responding! Unfortunately I still have the same issue after upgrading to 1.10.0. Which next version are you using?

vincentleeuwen avatar Aug 25 '22 15:08 vincentleeuwen

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

stale[bot] avatar Sep 15 '22 17:09 stale[bot]

@vincentleeuwen did you solve this problem? 🤔

jhkersul avatar Oct 18 '22 21:10 jhkersul

@jhkersul yeah I think the problem was that i was loading in stripe library client side, since the routing was client side and stripe was imported first time on that page. I think i read somewhere (had a look but can't find now) that the stripe lib has to be loaded from their servers for it to work properly. In Next terms, this means (I think) to load it on the first (server-side) render of _app.js. I moved it there and added the stripePromise to context to be fetched later when user navigates to /pay.

vincentleeuwen avatar Oct 19 '22 08:10 vincentleeuwen