Home > Software design >  useState hook doesn't instantly update the value?
useState hook doesn't instantly update the value?

Time:10-16

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>

  • Related