Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React.js State not updating in Event Listener in useEffect Hook

So, What I'm trying to do is add an event listener to a button that when pressed takes the value of a state and console log it. But the logged value never updates even after the multiple setState calls.

    useEffect(() => {
      const seamCarve = document.getElementById("process");
    
      seamCarve.addEventListener("click", (e) => {
        console.log(seamValue);
      });
    }, []);

And then there's the button that triggers it

          <div id="seamvalue">
            <Typography variant="h6" align="center">
              Seams Reduction:<span id="valueOfSeam"> {seamValue} </span>
            </Typography>
          </div>
    
          <Button
            id="leftslider"
            variant="contained"
            color="primary"
            onClick={() =>
              seamValue - 10 > 0 ? setSeamValue(seamValue - 10) : setSeamValue(0)
            }
          >
            <Typography>{"<"}</Typography>
          </Button>
    
          <Button
            id="rightslider"
            variant="contained"
            color="primary"
            onClick={() => setSeamValue(seamValue + 10)}
          >
            <Typography>{">"}</Typography>
          </Button>
    
          <Button id="process" variant="contained" color="primary">
            <Typography>Carve</Typography>
          </Button>

The value changes as I click on the sliders but when I press the Button with id="process" with an event listener associated with it, it only prints 20 even after updating the state.

like image 932
Akash Avatar asked Sep 07 '25 10:09

Akash


2 Answers

Don't use native DOM methods like addEventListener in React if at all possible - instead, work within React to achieve the same effect. It'll make a whole lot more sense and will require less convoluted code.

Put the click listener in the JSX syntax returned instead.

<Button
    id="process"
    variant="contained"
    color="primary"
    onClick={() => console.log(seamValue)}
>
    <Typography>Carve</Typography>
</Button>

If you absolutely cannot attach the click listener via React for some reason, then attach the listener again when the state changes. Also note that in order to start a function, you need a { after the =>, unless you're using concise return (which you aren't here).

useEffect(() => {
    const seamCarve = document.getElementById("process");
    const handler = () => {
        console.log(seamValue);
    };
    seamCarve.addEventListener('click', handler);
    return () => seamCarve.removeEventListener('click', handler);
}, [seamValue]);
like image 150
CertainPerformance Avatar answered Sep 09 '25 22:09

CertainPerformance


State variables don't update itself inside an EventListener. If you want to update and access some state inside an EventListener, look into useRef. Also, you need to replace your 2nd useState statement with useEffect since that's what you wanted to implement. A relevant post that should answer your question: Wrong React hooks behaviour with event listener

EDIT: as @CertainPerformance stated, event listeners like onClick can be directly used inside the jsx. My answer applies to the use of event listeners on the document.

like image 24
FireFighter Avatar answered Sep 10 '25 00:09

FireFighter