noOne
noOne

Reputation: 11

How to Fix Duplicated Paypal Button in React Strict Mode

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>

Upvotes: 1

Views: 1276

Answers (2)

Ivan J Flores
Ivan J Flores

Reputation: 19

I fixed it by downgrading to React 17.02

npm uninstall react react-dom

npm install [email protected] [email protected]

Upvotes: -1

Steve
Steve

Reputation: 8829

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... */])

Upvotes: 1

Related Questions