MoOx / pjax

Easily enable fast Ajax navigation on any website (using pushState + xhr)
MIT License
1.45k stars 124 forks source link

Not working with React event handlers #229

Closed julienc91 closed 4 years ago

julienc91 commented 4 years ago

Hi,

I'm using pjax along with some React components. I'm trying to disable some links programmatically, depending on the current state of the component, by using onClick/onClickCapture event handlers along with some stopPropagation and preventDefault methods. But this is not working as expected, as the links are still enabled.

Here is a small example to reproduce:

<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>Test pjax</title>
</head>
<body>
    <div><a href="/foo.html" onclick="return false">Go to /foo without React</a></div>
    <div id="root"></div>

    <script crossorigin src="https://cdn.jsdelivr.net/npm/pjax/pjax.min.js"></script>
    <script crossorigin src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
    <script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>
    <script crossorigin src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.26.0/babel.min.js"></script>

    <script>
        const pjax = new Pjax({
            selectors: ['body'],
            elements: 'a'
        })
    </script>

    <script type="text/babel">
        const App = () => {

            React.useEffect(() => {
                pjax.refresh()
            }, [])

            const handleClick = e => {
                e.preventDefault()
                e.stopPropagation()
                return false
            }

            return (
                <div onClickCapture={handleClick}>
                    <a onClick={handleClick} href="/foo.html">Go to /foo with React</a>
                </div>
            )
        }

        ReactDOM.render(<App />, document.getElementById('root'))
    </script>
</body>
</html>
<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>Test pjax</title>
</head>
<body>
    This page should not have been reached
</body>
</html>

Tested with the latest versions of Firefox and Chrome.

julienc91 commented 4 years ago

From what I understand, this is because React's SyntheticEvents are always processed after native events, which are the one used by Pjax. A quick test shows indeed that the isDefaultPrevented function returns false after the onClick handler is being called, but this is already too late.

The solution is... don't mix native events with React events, which means using a React-compatible version of pjax. Unfortunately for me, this won't be possible as my app is not a full-React app, but just isolated components here and there, but this is definitely not pjax's fault.

Anyway, if someone still manages to find a workaround for this particular case, I'd be happy to see it!