setState callback not waiting state to update

Tags: ,



I have this piece of code:

    handleMaxLevel = event => {
    this.setState({
      maxLevel: event.target.value
    }, (minLevel, maxLevel) => {
      let filter = this.state.filteredPlayers.filter(players => {
        return players.level > minLevel && players.level < maxLevel
      })
      this.setState({
        levelFilteredPlayers: filter
      })
    })
  }

Im calling this function on this piece of code:

 <TextField
        id="standard-number"
        label="Highest level"
        type="number"
        onChange={() => this.handleMaxLevel(this.state.minLevel, this.state.maxLevel)}
        InputLabelProps={{
          shrink: true,
        }}
  />

The things is im getting: TypeError: Cannot read property ‘value’ of undefined
It’s saying the problem is in this line: maxLevel: event.target.value.
I dont get it, isnt the callback supposed to wait for the first setstate to conclude so it executes?
Why it isnt reconizing the value set to maxLevel state?

Answer

Your syntax isn’t correct. When you call handleMaxLevel you should be passing it the event object. And the setState callback doesn’t need any arguments, it has access to the updated state already. So you onChange handler should just be this:

onChange={handleMaxLevel} // If we pass function directly, it will be given the event argument by default

and then in your setState callback, refer to the state values directly, as in the callback they will have been updated:

handleMaxLevel = event => {
    this.setState({
        ...this.state,
        maxLevel: event.target.value
    }, () => {
        let filter = this.state.filteredPlayers.filter(players => {
            return players.level > this.state.minLevel && players.level < this.state.maxLevel
        })
        this.setState({
            ...this.state,
            levelFilteredPlayers: filter
        })
    })
}

EDIT: I believe you need to spread old state too, to prevent the values being lost. Also, it’s probably better to just do this all in one setState call, rather than using the callback



Source: stackoverflow