I am building a Tenzies game and would like to implement a functionality that stores the number of previous rolls of the dice a user has to the localStorage and I already have a feature that renders the number of current rolls to the UI.
What I initially did was get a count that increases when the roll button is pressed. The rollCount
saves the number of rolls. prevRollCount
stores the previous count which should be the value of rollCount
. The issue is the storeRoll
which console logs the value I intended first then almost immediately logs undefined after setting the storeRoll
to zero on page refresh. The undefined
is logged until there is a win. Then the value of storeRoll
updates to the previous roll count as intended but on subsequent gameplay without page refresh, it adds the number of rolls to the previous roll.
On refresh, it outputs the stored value and then immediately logs undefined again and the loop continues as mentioned above.
const [tenzies, setTenzies] = useState(false);
let [rollCount, setRollCount] = useState(0);
const [prevRollCount, setPrevRollCount] = useState(rollCount);
const [storeRoll, setStoreRoll] = useState(JSON.parse(localStorage.getItem("die"))
);
Actually using a useEffect() and storing the code to retrieve in a state. Didn’t include a dependency array because that enabled the storeRoll
to be updated after discovering a win. tenzies
is updated in another useEffect
to true on a win.
useEffect(() => {
setStoreRoll(localStorage.setItem("die", JSON.stringify(prevRollCount))
);
if (tenzies) {
setStoreRoll(prevRollCount);
}
});
// Updates the roll count back to zero when there is a win
function updateRollCount() {
setTenzies(false);
setDice(allNewDice([1, 2, 3, 4, 5, 6]));
setRollCount(0);
setTime(0);
if (prevRollCount !== rollCount) {
setStoreRoll(prevRollCount);
}
}
// Saves the state of the dice we held or do not want to change on roll
function rollDice() {
if (!tenzies) {
setDice((prevValue) => {
return prevValue.map((die, index) => {
return die.isHeld
? { ...die }
: (die = allNewDice([1, 2, 3, 4, 5, 6])[index]);
});
});
}
else {
setTenzies(false);
setDice(allNewDice([1, 2, 3, 4, 5, 6]));
}
// Updates state for the number of rolls
setRollCount(prevValue =>
prevValue + 1
);
setPrevRollCount(prevValue => prevValue + 1);
}
`
What I basically want to do is that when a user wins a game and starts a new game, initialize a new state that helps store that value showing them their previous roll.
Here is the link to an updated Sandbox demo
2
Answers
I figured out the issue. It was because I was trying to get the value of storeRoll without checking whether it exists first.
The reason you are seeing undefined when console logging the prevRolls state right after setting it is due to React state updates being asynchronous. Setting state via setPrevRolls() will trigger a re-render, but the new state value won’t be available immediately.
There are a couple ways to fix this:
The issue is React hasn’t finished updating prevRolls when you try to log it immediately after setting. Use a callback, useEffect, or access later in component lifecycle to get the updated value.
Identifying the asynchronous state update behavior as the root cause is key to solving issues like this in React.