0

I need to render the next HTML code inside a component in React:

<form action="/procesar-pago" method="POST">
  <script
   src="https://www.mercadopago.com.ar/integrations/v1/web-payment-checkout.js"
   data-preference-id="$$id$$">
  </script>
</form>

I need to do something like this to render the button generated by the script inside my Grid.Column component.

<Grid>
  <Grid.Column>
      <form action="/procesar-pago" method="POST">
        <script
         src="https://www.mercadopago.com.ar/integrations/v1/web-payment-checkout.js"
         data-preference-id="$$id$$">
      </script>
    </form>
  </Grid.Column>
</Grid>

I have tried several different ways but none has worked for me.

Thanks!

0

1 Answer 1

1

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.

Sign up to request clarification or add additional context in comments.

3 Comments

Hello, I got the button in the bottom left corner of the page but I need it to appear as a child of another component to have it correctly positioned in the page, any suggestion? Thanks!
Hi, My suggestion is to use React Ref to append the button to your desired element after it loads on the page. I'll update the answer in a couple of minutes.
@MauricioAvendaño I updated the answer with the solution to move the button inside your desired element.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.