4

I have had this working before so I'm not sure if I'm making a silly mistake or it is somewhere else in my code.

Here is the simple component I am testing:

import React, { Component } from 'react'

class TestPropagation extends Component {
    handleBodyClick = () => {
        console.log(`Did not stop propagation`)
    }

    componentDidMount() {
        const body = document.querySelector(`body`)
        body.addEventListener(`click`, this.handleBodyClick)
    }

    componentWillUnmount() {
        const body = document.querySelector(`body`)
        body.removeEventListener(`click`, this.handleBodyClick)
    }

    render() {
        return (
            <div
                style={{
                    position: `absolute`,
                    top: `200px`,
                    left: `20%`,
                    width: `calc(80vw - 20%)`,
                    height: `500px`,
                    color: `white`,
                    background: `green`,
                    cursor: `pointer`,
                }}
                onClick={e => {
                    e.stopPropagation()
                    e.nativeEvent.stopImmediatePropagation()
                    console.log(`Clicked Div Handler`)
                }}
            >
                Test Propagation Component
            </div>
        )
    }
}

export default TestPropagation

If I am correct that should prevent the console log of Did not stop propagation from happening when I click the div, but it is not.

GalAbra
  • 5,048
  • 4
  • 23
  • 42
Taylor Austin
  • 5,407
  • 15
  • 58
  • 103

2 Answers2

1

The click event on the body is triggered before any react synthetic event. You will need to add a condition in your function like this:

handleBodyClick = e => {
  if (!e.target.className.includes('clickable')) {
    console.log('Did stop propagation');
  }
};

Then just add the class clickable on your component

Vincent D'amour
  • 3,746
  • 1
  • 27
  • 39
1

It's actually really interesting! Seems that the addEventListener precedes the onClick.

I managed to solve it by adding the same click listener to the test element, which worked as expected (stopped the click propagation to the body):

componentDidMount() {
    const body = document.querySelector('body');
    body.addEventListener('click', this.handleBodyClick);

    // This is me adding the click listener the same way you did
    document.getElementById('my_element').addEventListener('click', e => {
        e.stopPropagation();
        console.log('Clicked Div Handler 1');
    })
}

I hope this isn't considered a work-around, I'm still trying to understand this behaviour better.

EDIT: I found this question, which is basically the same (only without the React setting), but has no solution that achieves what you were asking.

GalAbra
  • 5,048
  • 4
  • 23
  • 42
  • 1
    Yeah since react does synthetic event listeners they must not fire off at the same time when mixing in pure js. This makes more since, great answer! – Taylor Austin Jul 10 '19 at 20:06