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

[React@17][[email protected]] Error - Can only create one Element of type card #154

Closed
thetrevdev opened this issue Jan 29, 2021 · 9 comments

Comments

@thetrevdev
Copy link
Contributor

Summary

When removing and adding a card element elsewhere in the dom it will throw the error
"Uncaught IntegrationError: Can only create one Element of type card."
This happens on React 17 but not React 16.

Other information

https://codesandbox.io/s/gracious-dawn-txrz7?file=/src/App.js

Maybe related to one of these issues but likely related to React 17
#153
#147
#152

Uncaught IntegrationError: Can only create one Element of type card.
    at new o (https://js.stripe.com/v3:1:2860)
    at https://js.stripe.com/v3:1:132846
    at e.<anonymous> (https://js.stripe.com/v3:1:133078)
    at e.create (https://js.stripe.com/v3:1:29636)
    at eval (https://txrz7.csb.app/node_modules/@stripe/react-stripe-js/dist/react-stripe.umd.js:498:34)
    at commitHookEffectListMount (https://txrz7.csb.app/node_modules/react-dom/cjs/react-dom.development.js:13903:30)
    at commitLifeCycles (https://txrz7.csb.app/node_modules/react-dom/cjs/react-dom.development.js:13947:15)
    at commitLayoutEffects (https://txrz7.csb.app/node_modules/react-dom/cjs/react-dom.development.js:15747:11)
    at HTMLUnknownElement.callCallback (https://txrz7.csb.app/node_modules/react-dom/cjs/react-dom.development.js:2746:18)
    at Object.invokeGuardedCallbackDev (https://txrz7.csb.app/node_modules/react-dom/cjs/react-dom.development.js:2770:20)
    at invokeGuardedCallback (https://txrz7.csb.app/node_modules/react-dom/cjs/react-dom.development.js:2804:35)
    at commitRootImpl (https://txrz7.csb.app/node_modules/react-dom/cjs/react-dom.development.js:15563:13)
    at unstable_runWithPriority (https://txrz7.csb.app/node_modules/scheduler/cjs/scheduler.development.js:646:12)
    at runWithPriority$1 (https://txrz7.csb.app/node_modules/react-dom/cjs/react-dom.development.js:7417:14)
    at commitRoot (https://txrz7.csb.app/node_modules/react-dom/cjs/react-dom.development.js:15466:7)
    at performSyncWorkOnRoot (https://txrz7.csb.app/node_modules/react-dom/cjs/react-dom.development.js:15031:7)
    at eval (https://txrz7.csb.app/node_modules/react-dom/cjs/react-dom.development.js:7457:30)
    at unstable_runWithPriority (https://txrz7.csb.app/node_modules/scheduler/cjs/scheduler.development.js:646:12)
    at runWithPriority$1 (https://txrz7.csb.app/node_modules/react-dom/cjs/react-dom.development.js:7417:14)
    at flushSyncCallbackQueueImpl (https://txrz7.csb.app/node_modules/react-dom/cjs/react-dom.development.js:7453:13)
    at flushSyncCallbackQueue (https://txrz7.csb.app/node_modules/react-dom/cjs/react-dom.development.js:7443:7)
    at discreteUpdates$1 (https://txrz7.csb.app/node_modules/react-dom/cjs/react-dom.development.js:15094:13)
    at discreteUpdates (https://txrz7.csb.app/node_modules/react-dom/cjs/react-dom.development.js:2636:16)
    at dispatchDiscreteEvent (https://txrz7.csb.app/node_modules/react-dom/cjs/react-dom.development.js:3987:7)
@thetrevdev
Copy link
Contributor Author

This is probably the culprit https://reactjs.org/blog/2020/08/10/react-v17-rc.html#effect-cleanup-timing

effect cleanup functions used to run synchronously but now runs asynchronously.

@christopher-stripe
Copy link
Contributor

Hey @thetrevdev, thanks for reporting.

That does indeed look like the issue. #153 fixed the problem when destroying then recreating an Element of the same type after some delay. But it seems recreating an Element of the same type immediately causes issues, which makes sense given the useEffect changes in React 17.

This will reproduce as well:

export default function App() {
  const [counter, setCounter] = useState(0);

  return (
    <div className="App">
      <Elements stripe={stripePromise}>
        <CardElement key={counter} />
      </Elements>
      <button onClick={() => setCounter(counter + 1)}>Replace Element</button>
    </div>
  );
}

I'm going to investigate a fix. In the meantime, one workaround would be to recreate a new Elements instance every time the <CardElement /> is recreated. So something like this (notice the key={counter} on the <Elements> provider):

export default function App() {
  const [counter, setCounter] = useState(0);

  return (
    <div className="App">
      <Elements stripe={stripePromise} key={counter}>
        <CardElement key={counter} />
      </Elements>
      <button onClick={() => setCounter(counter + 1)}>Replace Element</button>
    </div>
  );
}

I'm also curious how this comes up for you in practice. What in your app is making a <CardElement /> unmount and then remount immediately?

@thetrevdev
Copy link
Contributor Author

I think this is the fix but I am testing it now.
thetrevdev@6b0f2dc

@thetrevdev
Copy link
Contributor Author

This fixes the issue. I am putting up a PR after I add a unit test

@christopher-stripe
Copy link
Contributor

Wonderful, much appreciated.

@thetrevdev
Copy link
Contributor Author

Hmmm. I am having trouble reproducing it via unit tests

@thetrevdev
Copy link
Contributor Author

*Actually I am able to reproduce it I just don't see the error because I think elements is mocked. I'll probably have a working test shortly.

thetrevdev added a commit to thetrevdev/react-stripe-js that referenced this issue Jan 30, 2021
@dweedon-stripe
Copy link
Contributor

dweedon-stripe commented Jan 30, 2021

We need to make sure switching to useLayoutEffect doesn't cause issues (probably just warnings) with SSR. I haven't read through this to see if it is an actual issue, just wanted to flag it.

@christopher-stripe
Copy link
Contributor

Published fix in v1.2.2

We need to make sure switching to useLayoutEffect doesn't cause issues (probably just warnings) with SSR. I haven't read through this to see if it is an actual issue, just wanted to flag it.

Thanks 👍 This component doesn't run at all server-side, and already contains a useLayoutEffect (when the Element is first created).

CoCo-27 pushed a commit to CoCo-27/react-stripe-js that referenced this issue Feb 24, 2023
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

3 participants