2

I have search about this problem.

It must be pass function reference.

document.addEventListener("click", () => {}, false)

But what I do is still fire immediately.

Do I make some wrong?

Test code is below

export default function App() {
  const start = () => {
    console.log("start");
  };
  const click1 = () => {
    document.addEventListener("click", start);
  };

  const click2 = () => {
    const element = document.getElementById("p");
    element.addEventListener("click", start);
  };

  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>

      <button onClick={click1}>Click1</button>
      <hr />

      <p id="p">123</p>
      <button onClick={click2}>Click2</button>
    </div>
  );
}

// Click1 -  immediately, problem here

// Click2 - no immediately

https://codesandbox.io/s/reverent-grass-5fok7b?file=/src/App.js

What I expect

click first, add click event, no anything is log.

click second, log 'start'

actually output

click first, add click event, log start.

net
  • 39
  • 7

2 Answers2

2

You're handling a SyntheticEvent with your onClick handler and adding a native event listener at the document level. Adding the listener will complete before the event bubbles up to the top therefore you also see it execute for the original event.

If you don't want that to happen, stop the event from bubbling

const click1 = (e) => {
  e.stopPropagation();
  document.addEventListener("click", start);
};

Edit great-flower-cc31dy


FYI, you should also remove the DOM listener when your component unmounts

useEffect(() => () => document.removeEventListener("click", start), []);
Phil
  • 157,677
  • 23
  • 242
  • 245
1

Another option you might consider, keeping in mind the React paradigm to only attach listeners using React when possible, would be to attach the click handler to your App, rather than to the document with .addEventListener. (Best to only use addEventListener when there's no alternative with React handlers.)

function App() {
  const [started, setStarted] = React.useState(false);
  const tryLog = () => {
    if (started) {
      log();
    }
  };
  const log = () => console.log("event");
  return (
    <div className="App" onClick={tryLog}>
      <h1>Hello CodeSandbox</h1>

      <button onClick={() => setStarted(true)}>Click1</button>
      <hr />

      <p id="p">123</p>
      <button onClick={log}>Click2</button>
    </div>
  );
}

ReactDOM.createRoot(document.querySelector('.react')).render(<App />);
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<div class='react'></div>
CertainPerformance
  • 356,069
  • 52
  • 309
  • 320