I have a component which has to do some logic onClick.
const correctResponse: string = "C";
const [selectedResponse, setResponse] = useState<string|null>(null);
const onSubmitAnswer = () => {
class Coordinate {
x: number;
y: number;
constructor(x: number, y: number) {
this.x = x;
this.y = y;
}
}
let width: number = box0.current.getBoundingClientRect().width;
let height: number = box0.current.getBoundingClientRect().height;
let boxCoordinates: Array<Coordinate> = [];
for(let i=0;i<4;i )
{
let data = eval(`box${i 1}`);
boxCoordinates.push(new Coordinate(data.current.getBoundingClientRect().x, data.current.getBoundingClientRect().y));
}
if(Math.abs(boxCoordinates[0].x - box0.current.getBoundingClientRect().x) < width)
{
if(Math.abs(boxCoordinates[0].y - box0.current.getBoundingClientRect().y) < height)
{
setResponse("A");
}
}
else if(Math.abs(boxCoordinates[1].x - box0.current.getBoundingClientRect().x) < width)
{
if(Math.abs(boxCoordinates[1].y - box0.current.getBoundingClientRect().y) < height)
{
setResponse("B");
}
}
else if(Math.abs(boxCoordinates[2].x - box0.current.getBoundingClientRect().x) < width)
{
if(Math.abs(boxCoordinates[2].y - box0.current.getBoundingClientRect().y) < height)
{
setResponse("C");
}
}
else if(Math.abs(boxCoordinates[3].x - box0.current.getBoundingClientRect().x) < width)
{
if(Math.abs(boxCoordinates[3].y - box0.current.getBoundingClientRect().y) < height)
{
setResponse("D");
}
}
console.log(selectedResponse);
if(correctResponse === selectedResponse) {
console.log("ok");
}
else {
console.log("raspuns incorect");
}
Here's the full code, TS Playground
I observed by logging selectedResponse some strange behaviour.
Let's say I moved box0 over a box, and it matches the first if. The result that is logged is the answer previously stored in selectedResponse. Then if I press the button again, it will log the answer that it should've logged after the last press.
I don't understand why this happens. Example:
->app starts
->I move box0 over box1, so it sets the response to A
->console.log prints null (why? the response should've been set to A
Can anybody explain to me why does this behavior happen and how can I fix it? Thanks.
CodePudding user response:
One thing you need to be aware of is that your setResponse
function that you got from useState
is asynchronous.
This (generally speaking) means that when you call setResponse
your code will continue executing, regardless of if setResponse
has actually updated the value yet.
What I would assume is happening in your case is that you call setResponse("A")
but the console.log(selectedResponse)
gets executed before setReponse
has time to finish, hence why null
is printed (because null
is the default value you you gave it when you wrote useState<string|null>(null);
As another user suggested, an easy way to check if the value of selectedResponse
has actually updated is to use it inside useEffect
, like so:
useEffect(() => {
// This code will only be executed when selectedResponse's value changes
}, [selectedResponse])
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>