To handle the DOM elements outside the React root element, you can just handle the DOM changes directly. In this case, you can attach the script to the body element on the mounting of the component using lifecycle methods, then remove it on unmount, if don't needed anymore.
In class components you can do so on the componentDidMount:
componentDidMount() {
const script = document.createElement("script");
script.src = "https://www.mercadopago.com.ar/integrations/v1/web-payment-checkout.js";
script.id = "checkout-button";
script.async = true;
document.body.appendChild(script);
}
componentWillUnmount() {
document.body.removeChild(document.querySelector("#checkout-button")); // This will remove the script on unmount
}
In functional components using hooks:
useEffect(() => {
const script = document.createElement('script');
script.src = "https://www.mercadopago.com.ar/integrations/v1/web-payment-checkout.js";
script.async = true;
document.body.appendChild(script);
return () => {
document.body.removeChild(script); // This will remove the script on unmount
}
}, []);
Update:
In order to put the button inside your component instead of just loading on the body, you should get the rendered button then use React ref (to handle DOM events inside the react) and append it into your ref element. For more info see React Refs. I refactored the code to increase readability.
in Class components:
import React, { Component } from "react";
export default class App extends Component {
constructor() {
super();
this.buttonContainerRef = React.createRef(); // Creating ref element to assign as a form element attribute
}
componentDidMount() {
this.scriptLoader();
}
componentWillUnmount() {
this.scriptUnloader();
}
scriptLoader = () => {
const script = document.createElement("script");
script.src = "https://www.mercadopago.com.ar/integrations/v1/web-payment-checkout.js";
script.id = "checkout-button";
script.async = true;
document.body.appendChild(script);
window.addEventListener('load', this.scriptMover) // Runs when all the assets loaded completely
};
scriptUnloader = () => {
document.body.removeChild(document.querySelector("#checkout-button")); // Remove the script element on unmount
}
scriptMover = () => {
const button = document.querySelector(".mercadopago-button"); // Gets the button
this.buttonContainerRef.current.appendChild(button) // Appends the button to the ref element, in this case form element
};
render() {
return (
<Grid>
<Grid.Column>
<form action="/procesar-pago" method="POST" ref={this.buttonContainerRef} />
</Grid.Column>
</Grid>
);
}
}
In Functional components with Hooks:
import React, { useEffect, useRef } from "react";
const App = () => {
const buttonContainerRef = useRef(); // Creating ref element to assign as a form element attribute
useEffect(() => {
scriptLoader();
return () => {
scriptUnloader(); // Remove the script element on unmount
};
}, [])
const scriptLoader = () => {
const script = document.createElement("script");
script.src = "https://www.mercadopago.com.ar/integrations/v1/web-payment-checkout.js";
script.id = "checkout-button";
script.async = true;
document.body.appendChild(script);
window.addEventListener('load', scriptMover) // Runs when all the assets loaded completely
};
const scriptUnloader = () => {
document.body.removeChild(document.querySelector("#checkout-button"));
}
const scriptMover = () => {
const button = document.querySelector(".mercadopago-button"); // Gets the button
buttonContainerRef.current.appendChild(button) // Appends the button to the ref element, in this case form element
};
return (
<Grid>
<Grid.Column>
<form action="/procesar-pago" method="POST" ref={buttonContainerRef} />
</Grid.Column>
</Grid>
);
}
export default App;
I tested the code and it works fine, but feel free to ask if there was any issue.