Sam
Sam

Reputation: 1230

useState non-instantaneous updates break function

I have a sumButtonsDict state variable that stores a dictionary of objects. I've also built a simple addSumButton() function add a new object into the sumButtonsDict:

const [sumButtonsDict, setSumButtonsDict] = useState({})

function addSumButton(sum) {
    const dictKey = Object.keys(sumButtonsDict).length
    const sumButtonDict = {
        sum: sum,
        isActive: false
    }
    setSumButtonsDict(prevState => ({...prevState, [dictKey]: sumButtonDict}))
}

As you can see, the function stores every new dictionary item at a key corresponding to the index it's on (e.g., first item has key 0, second item has key 1...), but the correct key is derived from the count of objects already existing in sumButtonsDict.

When the component mounts, I add 5 new buttons using the following:

useEffect(() => {
    addSumButton(10)
    addSumButton(25)
    addSumButton(50)
    addSumButton(100)
    addSumButton(250)
}, [])

but only 1 ends up existing in sumButtonsDict. I suspect this is because setState() doesn't update the state variable immediately, and hence when I call Object.keys(sumButtonsDict).length it keeps on returning 0 even though the addSumButton() has run multiple times before.

How can I get around this?

Upvotes: 0

Views: 18

Answers (1)

Nicholas Tower
Nicholas Tower

Reputation: 85062

You're already using the function version of setSumButtonsDict to get the previous state, which is the right thing to do. You just need to move the other bits of code into the function too, so the entire calculation uses prevState:

function addSumButton(sum) {
  setSumButtonsDict(prevState => {
    const dictKey = Object.keys(prevState).length;
    const sumButtonDict = {
      sum: sum,
      active: false,
    }
    return {...prevState, [dictKey]: sumButtonDict}

  });
}

Upvotes: 2

Related Questions