evilworld
evilworld

Reputation: 43

setState callback not waiting state to update

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?

Upvotes: 0

Views: 110

Answers (2)

Ayushya
Ayushya

Reputation: 389

What's going wrong here is your function expects one argument

const handleMaxLevel = event => {
// ...
}

but, your invocation is sending two arguments

onChange={() => this.handleMaxLevel(this.state.minLevel, this.state.maxLevel)}

If you want to change your function to accept event and state variables variables:

// Change invocation like so:
onChange={event => this.handleMaxLevel(event, this.state.minLevel, this.state.maxLevel)}

// Change function definition like so:
const handleMaxLevel = (event, minLevel, maxLevel) => {
// ...
}

but, since you're just using state attributes inside the function you don't need to even pass them explicitly:

onChange={e => this.handleMaxLevel(e)}

this would let you make your function look like this:

const handleMaxLevel = event => {
    // access state attributes like this:
    const {minLevel, maxLevel} = this.state;
    // and now you also have access to the event value
    this.setState({ maxValue: e.target.value });
}

Upvotes: 0

Jayce444
Jayce444

Reputation: 9063

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

Upvotes: 2

Related Questions