-1

I'm new to React and trying to implement a few plain vanilla JS listeners outside of any components. The click events don't change the page content in any way, only the visibility of the dropdown menu, so I didn't think it made sense to have them inside a component.

When I click the profileIcon div, the dropdown becomes visible as expected. However, when I click anywhere on the body, the dropdown is then hidden. This happens even though I'm trying to stop propagation in the dropdown listener.

When I added console statements, I noticed that the body listener is getting called before the dropdown listener, essentially no matter what I do (e.g., order of addition, calling various timeout functions, changing the body listener to document.getElementById("root") etc.).

document.getElementById("profileIcon").addEventListener("click", (e) => {
    document.getElementById("dropdown").style.visibility = "visible"        
})

document.getElementById("dropdown").addEventListener("click", (e) => {
    console.log("dropdown")
    e.stopPropagation()
    e.preventDefault()
    e.stopImmediatePropagation()
})

document.body.addEventListener('click', function() {
    console.log("body")
    document.getElementById("dropdown").style.visibility = "hidden"
}, true)

The event listeners are all being added inside document.addEventListener("DOMContentLoaded") as it fails otherwise.

I really have no idea what to do here. Any ideas?

SOLUTION:

I removed true from the body listener, and changed the profileIcon listener to this:

document.getElementById("profileIcon").addEventListener("click", (e) => {
    e.stopPropagation()
    dropdown.style.visibility = "visible"
}, true)
SuperCodeBrah
  • 2,874
  • 2
  • 19
  • 33

1 Answers1

1

I noticed that the body listener is getting called before the dropdown listener

Because you are telling it to. If true is passed as third argument to addEventListener, the handler is executing in the capturing phase of the event, not the bubbling phase.

See What is event bubbling and capturing?

I really have no idea what to do here. Any ideas?

Don't pass true.

Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
  • Okay, I had taken out true and then it wasn't working at all. I realize now that it's because the listener on `profileIcon` was essentially getting immediately canceled because `body` was getting called first. I'll update the question with the modification to the `profileIcon` listener. – SuperCodeBrah Jun 08 '18 at 01:10
  • Correction to the above - the `body` listener was getting called immediately after the `profileIcon` listener and canceling it. – SuperCodeBrah Jun 08 '18 at 01:24
  • You should never (*almost*) manipulate the DOM directly when working with React. If you need to change the state of your components, do that within the components. – Geuis Jun 08 '18 at 01:29