Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Event listener attached to document will still be called after calling event.stopPropagation() #12518

Closed
vincentbel opened this issue Apr 2, 2018 · 5 comments

Comments

@vincentbel
Copy link

Do you want to request a feature or report a bug?

A bug.

What is the current behavior?

Event listener attached to document will still be called after calling event.stopPropagation() on target.

Example: (codesandbox link)

class App extends React.Component {
  componentDidMount() {
    document.addEventListener("click", this.handleClickOnDocument);
    window.addEventListener("click", this.handleClickOnWindow);
  }

  componentWillUnmount() {
    document.removeEventListener("click", this.handleClickOnDocument);
    window.removeEventListener("click", this.handleClickOnWindow);
  }

  handleClickOnDocument = e => {
    console.log("handling event on document");
  };

  handleClickOnWindow = e => {
    console.log("handling event on window");
  };

  render() {
    return (
      <div onClick={() => console.log("handling event on div")}>
        <button
          onClick={e => {
            e.stopPropagation();
          }}
        >
          Click Me
        </button>
      </div>
    );
  }
}

console will log:

handling event on document

What is the expected behavior?

handleClickOnDocument won't be called and no log in console.

Which versions of React, and which browser / OS are affected by this issue? Did this work in previous versions of React?

  • React: both 16.2.0 and 16.3.0
  • browser: Chrome 65
@gaearon
Copy link
Collaborator

gaearon commented Apr 2, 2018

e inside <div onClick> handler is a React synthetic event in your example. You're stopping its propagation through the React hierarchy, but for performance reasons it's technically implemented as an event listener on the document. So calling e.stopPropagation() doesn't affect the browser event and doesn't prevent it from reaching the document.

If you need to forbid it from reaching the document, you could put a ref on the div, and use addEventListener to add a DOM event listener directly. Then e.stopPropagation() in it will do what you expect.

Hope this helps!

@gaearon gaearon closed this as completed Apr 2, 2018
@vincentbel
Copy link
Author

Thanks for your reply.

I know that e inside <div onClick> is an React synthetic event. But it is still somehow weird that React can't stop propagate event to document. As far as I can see, attaching event to document is still commonly used, like react-click-outside.

By the way, will this issue get resolved if #2043 gets addressed?

@aweary
Copy link
Contributor

aweary commented Apr 2, 2018

@vincentbel this is because React's own listener is registered on the document as well, not on the element where the event originated from. Here's an example that explains what's happening.

@gaearon
Copy link
Collaborator

gaearon commented Aug 10, 2020

We're changing this in React 17 by attaching events to the root.

@gaearon
Copy link
Collaborator

gaearon commented Aug 11, 2020

If you want to try it, we released 17 RC yesterday with this change:
https://reactjs.org/blog/2020/08/10/react-v17-rc.html

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants