Unsupported prop change on Elements: You cannot change the `stripe` prop after setting it

Viewed 3483

Stripe Payment is completely work but i got the warning message on the console, "Unsupported prop change on Elements: You cannot change the stripe prop after setting it." Here is my code. I have no idea why the warning message is showing, what do i miss?

const Parent =() => {
        const stripePromise = loadStripe(PUBLISHABLE_KEY);
        <Elements stripe ={stripePromise}>
          <Child_component/>
        </Elements> 
}
export default Parent;

import {CardNumberElement, CardExpiryElement, CardCvcElement} from '@stripe/react-stripe-js';
const Child_component =() => {
        const handleChange = (event) => {
               //get the brand type
        };
        const handleFormSubmit = async ev =>{
           const cardElement = elements.getElement(CardNumberElement);
           const paymentMethodReq = await stripe.createPaymentMethod({
                    type: 'card',
                    card: cardElement
           });
           /// and send paymentMethodReq to the backend.
        }
   render(
       <Form className="" onSubmit={handleFormSubmit}>
        <div className="split-form full-width inline-block pt-4">
            <div className="row">
                <div className="col-12">
                    <label className="card-element">
                        Card number
                        <CardNumberElement
                        className="cardNumberElement"
                        onChange={handleChange}
                        />
                    </label>
                </div>
                <div className="col-8">
                    <label className="card-element">
                        Expiration date
                        <CardExpiryElement
                        onChange={handleChange}
                        />
                    </label>
                </div>
                <div className="col-4">
                    <label className="card-element">
                        CVC
                        <CardCvcElement 
                        onChange={handleChange}
                        />
                    </label>
                </div>
            </div>
        </div>
       </Form>
     )
 }
 export default Child_component;
3 Answers

Your problem is that in your Parent component you just do

const stripePromise = loadStripe(PUBLISHABLE_KEY);

What it means is actually on each render you will get new promise object (new stripePromise) every time, that's exactly what <Element> component is complaining about. What you should do instead, to not get new instance all the time on render, you should put loadStripe function in state, but because it is a function, you actually need to wrap it up in another function because of this - https://reactjs.org/docs/hooks-reference.html#lazy-initial-state.

So how should look like:

const [stripePromise, setStripePromise] = useState(() => loadStripe(PUBLISHABLE_KEY))

I had the same error.

what if we move the stripePromise variable outside the functional component? – Noman Gul Feb 5 at 17:35

Noman's comment is the ideal solution for most of cases, but that doesn't work if the Stripe account depends on React state. This usually happens if you are building apps with Stripe Connect.

In that case, you should use useMemo to memoize the promise.

const Parent = ({ stripeAccount }) => {
  const stripePromise = useMemo(
    () => loadStripe(PUBLISHABLE_KEY, { stripeAccount }),
    [stripeAccount],
  )

  return (
    <Elements stripe={stripePromise}>
      <Child_component/>
    </Elements> 
  )
}

Otherwise, the component loads stripe every re-render!

Example using Noman's comment and just moving the promise outside of the functional component

what if we move the stripePromise variable outside the functional component? – Noman Gul Feb 5 at 17:35

This is working perfectly for me.

const stripePubKey = 'your-stripe-publishable-key';
const stripePromise = loadStripe(stripePubKey);

const Parent: React.FC = () => {
  return (
    <Elements stripe={stripePromise}>
      <Child />
    </Elements> 
  )
}
Related