Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React Router Link reloading page : Conflict with external event

I'm using React Router's Link component to handle page transition in my app.

My app is included in an external web page, which has some scripts (namely Google Tag Manager) that define events on links on the document level.

This causes a conflict with Link events : page is always reloading when clicking on a link.

I tried to stop propagation on my Link component with an onClick callback, with no luck : <Link onClick={(e) => { e.stopPropagation(); }} [...]>...</Link>

I see that Link events are also defined on the document level, so I don't know how to stop the external events.

Any clue on this one ?

Thank you !

like image 337
Henry Boisgibault Avatar asked Oct 16 '22 00:10

Henry Boisgibault


1 Answers

Update: It seems that there's no simple way to do this without rendering the whole app inside an iframe.

If you don't mind doing that though, it's easy enough (taken from How to set iframe content of a react component):

const Frame = ({ children }) => {
    const [ref, setRef] = useState(null)
    const mountNode = ref?.contentWindow.document.body

    return (
        <iframe title="iframe" ref={setRef}>
            {mountNode && ReactDOM.createPortal(children, mountNode)}
        </iframe>
    )
}

Then, wrap your main app as a child of the Frame component. Clicks inside an iframe will not bubble up to the parent window, as detailed in Capture click on div surrounding an iframe.

Here's a CodeSandbox demo showing this approach.


Original (non-functioning) answer below

On your App or Router component:

const blockClicks = useCallback((e) => {
    const { target } = e
    const { nodeName, href } = target
    if (
        target.closest('#root-id') &&
        nodeName === 'A' &&
        href &&
        (/^https?:\/\//.test(!href) ||
        href.startsWith(window.location.origin)
    )) {
        // amend logic specific to your use case
        // - we want to avoid blocking irrelevant clicks
        e.stopPropagation()
    }
})

useEffect(() => {
    document.addEventListener('click', blockClicks, true)

    return () =>
        document.removeEventListener('click', blockClicks, true)
})
like image 99
Lionel Rowe Avatar answered Oct 19 '22 02:10

Lionel Rowe