Noah Wardlow
Noah Wardlow

Reputation: 55

How to load Stripe promise outside of React component?

I am making a Stripe promise in React, their docs say to load the promise outside of the component like so:

import {Elements} from '@stripe/react-stripe-js';
import {loadStripe} from '@stripe/stripe-js';

// Make sure to call `loadStripe` outside of a component’s render to avoid
// recreating the `Stripe` object on every render.
const stripePromise = loadStripe('pk_test_TYooMQauvdEDq54NiTphI7jx');

const App = () => {
  return (
    <Elements stripe={stripePromise}>
      <MyCheckoutForm />
    </Elements>
  );
};

My problem is that I'm getting the public key from an API and storing it in redux (we connect to several different companies). Loading it within the component is causing re-renders:

import React from "react";
import { Elements } from "@stripe/react-stripe-js";
import { loadStripe } from "@stripe/stripe-js";
import { useSelector } from "react-redux";
import ExpressCheckout from "./ExpressCheckout";

const ExpressContainer = () => {
  const stripe_PK = useSelector(
    (state) => state.company.presenter.data_stripe_pk
  );
  const stripePromise = loadStripe(stripe_PK);
  return (
    <Elements stripe={stripePromise}>
      <ExpressCheckout />
    </Elements>
  );
};

export default ExpressContainer;

I've tried to load the redux state before the component with getState() but it comes back blank.

Upvotes: 2

Views: 2245

Answers (1)

Nolan H
Nolan H

Reputation: 7459

You'll want to defer calling loadStripe until you get a valid value for the PK out of your selector.

When you provide null to the stripe prop of <Elements />, it defers initialization. You can change one time from a null value to a promise that resolves to a Stripe object, but then changing the stripe prop is not allowed.

stripe

required Stripe | null | Promise<Stripe | null>

A Stripe object or a Promise resolving to a Stripe object. The easiest way to initialize a Stripe object is with the Stripe.js wrapper module. After this prop has been set, it can not be changed.

You can also pass in null or a Promise resolving to null if you’re performing an initial server-side render or when generating a static site.

I've rigged up an example here with setTimeout to simulate a delayed load of the key and then useEffect to trigger calling loadStripe: https://codesandbox.io/s/react-stripe-js-delayed-key-effect-boxmz

This is not the only way to achieve this, but it illustrates the idea.

Upvotes: 2

Related Questions