How to Fix Duplicated Paypal Button in React Strict Mode

941 views Asked by At

Hi guys would like to know how to fix this issue after updating to React 18 I have a duplicated button due to the useEffect while in StrictMode. Any guide how to unsubscribe to this API call or maybe fix it using a proper cleanup. Thanks in advance.

const paypalbutton = useRef();

useEffect(() => {

    const addPayPalScript = async () => {

        const { data } = await axios('/api/config/paypal');
        script = document.createElement('script');
        script.type = 'text/javascript';
        script.src = `https://www.paypal.com/sdk/js?client-id=${data}`;
        script.async = true;
        script.onload = async () => { setSdkReady(true) };

        paypalbutton.current.appendChild(script)
    };

  // inside render()
        <li ref={paypalbutton} id="paypal-button" className="row center">
     
          </li>
2

There are 2 answers

5
Steve On

React strict mode deliberately runs the useEffect callback twice to catch misuse of useEffect, which is what's happening here.

You'll need to do two things:

  1. Make your asynchronous side effect cancellable; and
  2. Return a cleanup function that will
    • cancel the side-effect if it's in progress; or
    • undo the side effect if it completed.
useEffect(() => {
    const controller = new AbortController();
    let script

    const addPayPalScript = async () => {
        const { data } = await axios.get(
            '/api/config/paypal',
            { signal: controller.signal }
        )

        script = document.createElement('script')
        script.type = 'text/javascript'
        script.src = `https://www.paypal.com/sdk/js?client-id=${data}`
        script.async = true
        script.onload = () => {
            setSdkReady(true)
        }

        paypalbutton.current.appendChild(script)
        completed = true
    }

    let completed = false

    addPayPalScript().then(() => {
        completed = true
    })

    return () => {
        controller.abort()

        if (completed) {
            paypalbutton.current.removeChild(script)
        }
    }
}, [/* not sure what goes here... */])
1
Ivan J Flores On

I fixed it by downgrading to React 17.02

npm uninstall react react-dom

npm install [email protected] [email protected]