0

I have an App component and a Box component, which is a child of the App. I want to listen to click on the App component,t and if a Box was clicked, I don't want that event to propagate.

This is the code I have written:

App.js:

function App() {
  const handleClick=()=>{
    console.log("Clicked on the app")
  }
  document.addEventListener('click', handleClick, true);
  return (
    <div className="wrapper">
    <Box ></Box>
    </div>
  );
}
export default App;

Box.js:

export function Box(){
    const onSelect=(e)=>{
        e.stopPropagation();
    }
    return (
        <div tabIndex="0" onClick={onSelect}>Box</div>
    )
}

However, I observe two things:

  • Every click produces two console statements instead of one
  • Click on Box does not stop propagation and the console statements are still printed twice

Why is this happening and how do I get around it?

Youssouf Oumar
  • 29,373
  • 11
  • 46
  • 65
codingsplash
  • 4,785
  • 12
  • 51
  • 90
  • try https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault – baklazan Apr 27 '23 at 11:39
  • I thought you called `stopPropagation` in a `select` or `change` event. In fact you called it inside `click`. My guess is, since react registers single function on the root of the page and checks for `event.currentTarget`, both will fire. What you can do is to check if `event.currentTarget.className` or `event.currentTarget.nodeName` etc. to check if it is a div or not and decide what to do based on that. Ex: inside handleClick: `if(event.currentTarget.nodeName === "DIV"){return}`. You need to pass the event – ibrahim tanyalcin Apr 27 '23 at 11:43
  • 1
    Just remove the true option from your event listener. `document.addEventListener('click', handleClick)`. Also use event listeners like this inside `useEffect`. – Junaed Siam Apr 27 '23 at 11:49
  • 1
    It is not about the `true` option but a wrong React implementation of the component. Check my below answer. – Youssouf Oumar Apr 28 '23 at 10:51
  • Does this answer your question? [Why is my function being called twice in React?](https://stackoverflow.com/questions/50819162/why-is-my-function-being-called-twice-in-react) – 0stone0 Apr 28 '23 at 11:01

1 Answers1

2

In development, with StrictMode since version 18, React mounts, unmounts, and then mounts components on the initial render to check for bugs, and non "correct" React code.

And the check seems to have done its work, because, you need to add your addEventListener in a useEffect with a clean-up function, that removes the event handler from memory before the component re-renders again.

Otherwise, a component being designed to render multiple times, you register a new event handler per render.

function App() {
  useEffect(() => {
    const handleClick = () => {
      console.log("Clicked on the app");
    };
    document.addEventListener("click", handleClick);
    return () => {
      document.removeEventListener("click", handleClick);
    };
  }, []);
  return (
    <div className="wrapper">
      <Box></Box>
    </div>
  );
}
export default App;

Youssouf Oumar
  • 29,373
  • 11
  • 46
  • 65
  • YOu could just close this as one of the duplicates regarding strict mode – 0stone0 Apr 28 '23 at 11:02
  • Hi @0stone0! I know there are StrictMode-related threads. I closed so many myself, like this [one](https://stackoverflow.com/questions/75715636/user-is-being-created-twice-in-nextjs-13-with-firebase-and-nextauth). But no one that I found would fix his problem right away because he is not using `useEffect`. Would he know that because React runs twice the component, he should use `useEffect` with a clean-up? Others advise disabling StrictMode, which is bad. – Youssouf Oumar Apr 28 '23 at 11:12