2

I am a React beginner and I am trying to create a small game within the browser where an array of numbers is displayed, and the user must correctly choose the sum of all the numbers from a multiple choice selection. I have a button that starts the game via an onClick callback as shown below.

    const [sequence, setSequence] = useState([]);
    const [sum, setSum] = useState(0)
    const [countdown, setCountdown] = useState(10);
    const [multipleChoice, setMultipleChoice] = useState([]);

    const createSequence = () => {
        let newSequence = []
        for (let i = 0; i < 6; i++) {
            newSequence.push(Math.floor(Math.random() * 9) + 1);
        }
        setSequence(newSequence);
    }

    const createRandomAnswers = () => {
        let multipleChoiceArray = someRandomArrayFunction();
        setMultipleChoice(multipleChoiceArray);
    }

    const calculateSum = () => {
        // calculates sum of current number sequence and updates sum state
        let total = 0;
        for (var i in sequence) {
            total += sequence[i];
        }
        setSum(total);
    }

    const createGame = () => {
        createSequence();
        console.log("calculating sum")
        calculateSum();
        createRandomAnswers();
    }

    return (
        <>
            <p> {sum}</p>
            <h2>{sequence}</h2>
            <button onClick={createGame}>Start Game</button>
            <Choice value={multipleChoice[0]} />
            <Choice value={multipleChoice[1]} />
            <Choice value={multipleChoice[2]} />
        </>
    );

These three functions each update state variables using state hooks. However, each correct values of each are not in sync.

For example, if I had an array sequence of [1, 2, 3, 4], the sum should display as 10. When createGame is called, the sequence updates, but the sum does not update until the second time createGame is called, at which point the sequence updates to a new number, and the sum is set to 10.

createGame();
// Sequence displayed as [1, 2, 3, 4]
// sum displayed as 0 (initial state)
// multiple choice displayed as blank (initial state)

createGame();
// Sequence updates to random, e.g. [3, 1, 3, 2]
// sum displayed as 10 (sum from previous sequence)
// multiple choice displayed as blank (initial state)

Why do these values lag behind and update one at a time, when they are all being called within createGame? I know I am probably misunderstanding some core React principle, but any help would be appreciated.

5
  • 1
    Welcome to SO! I don't see any React code here. Can you show a minimal reproducible example please rather than pseudocode? "These three functions each update state variables using state hooks" -- please show, don't tell, because sometimes the devil is in the details, like how you're making these calls or whether these functions are doing no-nos like mutating state or reading stale state. These are very common bugs in React. Commented Jul 10, 2021 at 18:44
  • 1
    Refer to this question. You'll probably find what you're looking for :) Commented Jul 10, 2021 at 18:48
  • @ggorlen I updated my code above, sorry not sure of the best way to clarify edits correctly, but that code should be more clear. Reading up on the other response, that may clarify my problem Commented Jul 10, 2021 at 18:50
  • This is a great clarification, thanks. Yes, the answer is that when you call setFoo you won't see the new values until the next render. calculateSum is reading the old empty sequence. Commented Jul 10, 2021 at 18:52
  • You were both very helpful, thank you! Commented Jul 10, 2021 at 22:27

1 Answer 1

2

This is because useState hooks work asynchronously, meaning that the change does not occur immediately after the setState function is called. If you want that some action 'A' happens immediately after change in state 'total' then you can use useEffect and add a dependency for it such that when XYZ changes(total in your case), setSum(value). Make 'total' as state variable and do these changes:

const [total, setTotal] = useState(0)

const calculateSum = () => {
    // calculates sum of current number sequence and updates sum state
    let total = 0;
    for (var i in sequence) {
        total += sequence[i];
    }
    setTotal(total);
}


 useEffect(() => {
        setSum(total);
         }, [total]);
Sign up to request clarification or add additional context in comments.

2 Comments

Your answer would be greatly improved if you showed and explained an example to answer the question here. Links are best used to point to futher information/resources after providing the answer. Better post = more reputation.
@WorkingMatt Thanks for the correction. I am a new contributor here so I will try not to do such mistakes in the future. I edited the answer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.