SVY
SVY

Reputation: 47

ReactJS's setState confusion with select drop down

I'm getting a mis-ordered response in React's setState with a select drop down I'm using. It's giving me the value of the previously selected option. When I first select something it comes out as blank, but the second select will give me the one I chose before.

So, first pick: "Green" results to empty Second pick: "Red" will give me 'gre' as result

I know I'm missing something, perhaps I'm not binding it correctly?

class Main extends React.Component {
    constructor(props) {
       super(props);
       this.state = {
          typeValue: ''
        }
     this.changeHandler = this.changeHandler;
     this.expressValue = this.expressValue.bind(this);
    }

    expressValue(e) {
       this.setState({
           typeValue : e.target.value
       });
       console.log('this type val state is: ' + this.state.typeValue);
    }

    render() {
         return (
            <div>
                <TypeSelect changeHandler={this.expressValue} />
            </div>
         )
    }
};

class TypeSelect extends React.Component {
   constructor(props) {
      super(props);
   }

   render() {
        let options = {
           'default': 'Choose a category',
           'red': 'Red',
           'blu': 'Blue',
           'gre': 'Green',
         }
       return (
            <select name="name_type" id="name_type" onChange={this.props.changeHandler}>
            {
                  Object.keys(options).map(function(key){
                   return (
                       <option key={key} value={key}>{options[key]}</option>
                     )
                 })
               }
           </select>
     )
   }
};

Upvotes: 1

Views: 2373

Answers (2)

Robert Taussig
Robert Taussig

Reputation: 581

Roman's got it right, but I also wanted to point something else out:

this.changeHandler is not defined in your Main react component. And even if it was, you didn't bind it to (this).

In your constructor, change the line:

this.changeHandler = this.changeHandler;

to:

this.changeHandler = this.changeHandler.bind(this);

and then you would define a function by that name as you did expressValue().

Upvotes: 1

Roman Maksimov
Roman Maksimov

Reputation: 1635

this.setState() changes the state asyncronously. It means, the value will be really changed with a bit delay. Usually it's not a problem, when you are relaying on state after compomemnt update. But there you are trying to take a new value immediately. This won't work, as at this time you still don't have this value in the state. In your particular case there are two ways.

First way. Use your origin value instead of state value in expressValue function:

expressValue(e) {
   this.setState({
       typeValue : e.target.value
   });
   console.log('this type val state is: ' + e.target.value);
}

Second way. Show the message after the compoment was updated, for example, in render method, wich is calling every time the state was changes.

render() {
     console.log('this type val state is: ' + this.state.typeValue );
     return (
        <div>
            <TypeSelect changeHandler={this.expressValue} />
        </div>
     )
}

Upvotes: 1

Related Questions