Home > Blockchain >  React useState not updating state when using callback function
React useState not updating state when using callback function

Time:01-18

When i click the button to run rollDice() it is not updating state. I can not figure out why because it is updating correctly on my console logs. But the state is not refreshing.

`import React from "react" import Die from "./Die"

export default function App() {

let diceObj = allNewDice()
    diceObj = diceObj.map((dice) => ({value: dice, isHeld: false}))
    
const [dice, setDice] = React.useState(diceObj)
console.log("refreshed")

function allNewDice() {
    const newDice = []
    for (let i = 0; i < 10; i  ) {
        newDice.push(Math.ceil(Math.random() * 6))
    }
    return newDice
}



function rollDice() {
    setDice(prevState => {
        for (let i = 0; i < prevState.length; i  ){
            prevState[i].value = Math.ceil(Math.random() * 6)
        }
        console.log(prevState)
        return prevState
    })
    console.log(dice)
}

const diceElements = dice.map(die => <Die value={die.value} />)

return (
    <main>
        <div className="dice-container">
            {diceElements}
        </div>
        <button className="roll-dice" onClick={rollDice}>Roll</button>
    </main>
)

}`

I got it working another way but its bothering me because this seems like it should work too..

CodePudding user response:

you are not updating!

you cannot update the value of prevState so when you are returning prevState after your changes your are actually returning the same prevState therefore the component does not render because it only does when the prev value is different from the new, which is not the case

one solution is to create a copy of prevState you update it then you return it :

function rollDice() {
setDice(prevState => {
    var newValue = [...prevState];
    for (let i = 0; i < prevState.length; i  ){
        newValue[i].value = Math.ceil(Math.random() * 6)
    }
    return newValue 
})
}

CodePudding user response:

for (let i = 0; i < prevState.length; i  ){
  prevState[i].value = Math.ceil(Math.random() * 6)
}

This code is mutating the previous state, but react expects state to be immutable. So after you return prevState, react compares the old and new states, sees that they are the same array, and thus skips rendering because it thinks nothing has changed.

The fix is to create a new array and return that. For example:

setDice(prevState => {
  const nextState = prevState.map(die => {
    return {
      ...die,
      value: Math.ceil(Math.random() * 6)
    }
  });
  return nextState;
})

CodePudding user response:

Something like this can clean up your code:

function rollDice() {
for(let i = 0; i < dice.length; i  ) {
    const newValue = Math.ceil(Math.random() * 6);
    setDice(prevState => [
        ...prevState.slice(0, i),
        {
          value: newValue,
          isHeld: false,
        }
    ])    
}

Also I noted you could just create an object in the allNewDice() function and you wouldn't need to do the map up at the top.

  • Related