"Error: zoid destroyed all components↵" error in reactjs nextjs

Viewed 4026

I have this paypal integration in my nextjs application. when I load the page everything loads well but when i navigate way from the page and back. It throws an error

unhandled_error: zoid destroyed all components↵

Paypal does not provide any additional information on this error at all.

My code is just a normal component

componentDidMount() {
    paypal
.Buttons({
  createOrder: (data, actions)=> {
    return actions.order.create({
      purchase_units: [{
          amount: {
            currency_code: "USD",
            value: amount,
          },
        }],
    });
  },
  onCancel: function(data){
    //console.log(data)

  },
  onError: function(err){
    console.log(err)
  }
})
.render("#paypal");
 }




<div id="paypal" className=""></div>

what am i doing wrong

3 Answers

This is related to a currently open issue in the Paypal Buttons "Zoid" dependency, related to a bug in the way it's handling React components.

Currently, there is an open PR that has not yet been completed/approved, but is on the way to solve this issue. After this it's solved, next up the Paypal team will have the job of upgrading this dependency to finally fix the bug.

Disclaimer: I'm same who created the issue and submitted the PR, I'll be updating this comment once it's merged.

This is because you are implementing it the wrong way. PayPal has a separate page with documentation for Single Page Applications.

Edit: Make sure you import React and ReactDOM in your Next.js app. As you can see in their React example.

This is the problem of Paypal on embed JavaScript, create button script piece ran before paypal initialized. My solution is load the PayPal script before run create button script

function loadAsync(url: string, callback: () => void) {
  const s = document.createElement('script');
  s.setAttribute('src', url);
  s.onload = callback;
  document.head.insertBefore(s, document.head.firstElementChild);
}

export const loadScriptPaypal = (html: string) => {
  const regex = /<script\b[^>]*>([\s\S]*?)<\/script>/gm;
  const scripts = html.match(regex);
  let pureHtml = html;
  const src = scripts[0].match(/src="(.*?)"/)[1];
  const func = scripts[1].replace(/<\/script>|<script>/g, '');
  loadAsync(src, () => {
    eval(func);
  });
  scripts.forEach(script => {
    pureHtml = pureHtml.replace(script, '');
  });
  return pureHtml;
};

Related