0

This takes place in a functional component:

import {useEffect} from 'react';
let [clickedOnPiece, setClickedOnPiece] = useState(false);
let [testRender, setTestRender] = useState(false);

useEffect(() => {
  testRenderFunction();
}, [])

function testRenderFunction() {
  let el = <div onClick={onClickHandler}>Click me</div>;
  setTestRender(el);
}

function onClickHandler() {
  if (clickedOnPiece) {
    console.log("already clicked")
    return
  }
  console.log(clickedOnPiece); //returns false the 1st & 2nd time.
  setClickedOnPiece("clicked");
}

return (
  <>
    {testRender}
  </>
)

When I click on div for the first time, I wait until setClickedOnPiece("clicked") successfully updates clickedOnPiece to "clicked". (I check this with React Developer Tools).

When I click div the 2nd time, it doesn't log the new change in state. It still logs clickedOnPiece as false. Why is this?


tonitone120
  • 1,920
  • 3
  • 8
  • 25
  • It's working properly. You can see it here https://codesandbox.io/s/issue1-gd9y2 – jonybekov Dec 01 '20 at 18:02
  • Thanks @jonybekov I was actually simplifying my original problem too much. If you have a look at my question now, I've updated it to show the way in which I insert the div, which I believe causes the problem. If you were able to have a look at this that'd be appreciated – tonitone120 Dec 02 '20 at 01:51

4 Answers4

0

Okey this problem is because useState is asyncronus. u can read more about this useState set method not reflecting change immediately.

I think the solution is add useEffect like this.

useEffect( () => {
  console.log(clickOnPiece);
 }
, [clickOnPiece])
ardoYep
  • 107
  • 3
  • 15
0

If you want to toggle the state, you could do something like this:

let [clickedOnPiece, setClickedOnPiece] = useState(false);

const onClickHandler = () => {
  // set the value of clickedOnPiece to the opposite of what it was
  // i.e. if it was 'true', set it to 'false'.
  setClickedOnPiece(!clickedOnPiece);
  console.log(clickedOnPiece);
}

// call the onClickHandler on click
<div onClick={()=>onClickHandler()}>Click me</div>
Thomas Allen
  • 725
  • 5
  • 17
  • 30
0

Looks like you are toggling

let [clickedOnPiece, setClickedOnPiece] = useState(false);

const onClickHandler = () => {
  console.log(clickedOnPiece);
  setClickedOnPiece(!clickedOnPiece);
}

console.log(clickedOnPiece);

<div onClick={onClickHandler}>Click me</div>

After setting state, don't console immediately because state is an asynchronous.

akhtarvahid
  • 9,445
  • 2
  • 26
  • 29
0

onClickHandler references the old, previous variable, clickedOnPiece. I believe this is because onClickHandler is not defined in the return statement part of the functional component which would have allowed it a new onClickHandler body to be created each time. Instead, we have the old onClickHandler continually referencing the old clickedOnPiece.

This problem is known as 'stale closures' - a concept I found discussed well at the bottom of this article

tonitone120
  • 1,920
  • 3
  • 8
  • 25