Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

100
Views
ReactJS unexpected behavior in window event

Stuck on an issue that is probable easy to fix. I have the following React code (which can be found at CodeSandbox):

export const App = ()=> {
  const [toggle,setToggle] = useState(false);

  const setItemToggle = (e) => {
    e.stopPropagation()
    e.target.tagName==="H1" ? setToggle(!toggle) : setToggle(false)
    e.preventDefault()
  }

  useEffect(()=>{
    window.addEventListener("click",setItemToggle,false);
    return () => window.removeEventListener("click",setItemToggle,false);
  },[])


  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <h2>Current Value Of toggle is {toggle ? "True" : "False"}</h2>
    </div>
  );
}

When you click on the <h1>Hello CodeSandbox</h> I expected the toggle to change accordingly; however, it changes once and doesn't toggle after that. Clicking outside of the element does change the toggle to false. I know it has to do with the eventListener added to the Window but I can't track it down. Thanks for any help.

about 4 years ago · Juan Pablo Isaza
3 answers
Answer question

0

You have a stale prop problem

  • since the event handler you assign to the event listener is using the initial closure it was created in (so it doesn't see changes to the closed-over toggle value),
  • and you don't set the function as a dependency to the useEffect invocation so a new version of the function never gets used.
    Had you omitted the empty dependency array altogether, this would have worked, with the caveat that you would be continuously re-registering event handlers.
    • I recommend using the eslint-plugin-react-hooks linter – it would have caught this.

The easy way to fix this is to not close over (refer to) the toggle variable at all in the event handler at all by using the function form of setState: setToggle(toggle => !toggle).

about 4 years ago · Juan Pablo Isaza Report

0

You are simply changing the state value by doing setState(!state). This pattern does not guarantee that you have the correct value of state. You are better off using the functional pattern:

import { useEffect, useState } from "react";
import "./styles.css";

const App = () => {
  const [toggle, setToggle] = useState(false);

  const setItemToggle = (e) => {
    e.stopPropagation();
    e.target.tagName === "H1"
      ? setToggle((toggle) => !toggle)
      : setToggle(false);
    e.preventDefault();
  };

  useEffect(() => {
    window.addEventListener("click", setItemToggle, false);
    return () => window.removeEventListener("click", setItemToggle, false);
  }, []);

  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <h2>Current Value Of toggle is {toggle ? "True" : "False"}</h2>
    </div>
  );
};

export default App;

setState(prevState => !prevState) is a sure way to ensure you have the correct previous value of state. This is the ideal way to set state when new value of state depends on previous value of state.

Sandbox Link

The problem is that your function is unaware of the new value of state, one more way to tackle is using the dependancy array. As the name suggests you are defining the dependencies of the your code in the array. Just pass it as the second param to useEffect and you should be good to go:

import { useEffect, useState } from "react";
import "./styles.css";

const App = () => {
  const [toggle, setToggle] = useState(false);

  useEffect(() => {
    const setItemToggle = (e) => {
      e.stopPropagation();
      e.target.tagName === "H1" ? setToggle(!toggle) : setToggle(false);
      e.preventDefault();
    };

    window.addEventListener("click", setItemToggle, false);
    return () => window.removeEventListener("click", setItemToggle, false);
  }, [toggle]);

  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <h2>Current Value Of toggle is {toggle ? "True" : "False"}</h2>
    </div>
  );
};

export default App;

We are once again tackling the problem of incorrect state value but this time by rerunning the code inside the useEffect callback and hence redefining the function setItemToggle.

Link

Note: Also if a function is only relevant inside useEffect, best to define it there only. This is also one of the pros of using hooks instead of classes. Your relevant code is in one place.

about 4 years ago · Juan Pablo Isaza Report

0

You can just add onClick to h1 element and pass a function directly there.

<h1 onClick={() => setToggle(!toggle)}>Hello CodeSandbox</h1>

some good resource on the topic of Handling Events in react can be found here and working sandbox of what I present can be found here

about 4 years ago · Juan Pablo Isaza Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!