6

I'm attempting to update the state of a Parent component after the user updates the value of a Child component's select element.

Whilst I've got it somewhat working, I've noticed that when I fire the onChange event on my select, it will always return the previous value instead of the value that has just been selected.


class Parent extends Component{
    constructor(props){
        super(props);
        this.state = { data: {
            condition: "any"
        }};
    }

    update = data => {
        this.setState({ data: { 
            ...this.state.data, 
            ...data 
        }});
        
        // This gets called every time I change the value of my select element.
        console.log(this.state.data);
    }

    render(){
        return (
            <Child
                condition={this.state.data.condition} 
                onUpdate={data => this.update(data)} />
        );
    }
}

class Child extends Component{
    updateParent = data => {
        this.props.onUpdate(data);
    }

    render(){
        const options = [
            ["any", "Any Condition"], 
            ["new", "Brand New"], 
            ["used", "Used"]
        ];

        return (
            <select 
                defaultValue={ props.selected } 
                onChange={({ target }) => this.updateParent({ condition: target.value })}>
                    { options.map(([id, name]) => (
                        <option key={id} value={id}>{ name }</option>
                    )}
            </select>
        );
    }
}

In this example, if I select used, the console will return any. Then, if I select new, the console will return used.

GROVER.
  • 4,071
  • 2
  • 19
  • 66
  • Is it the console where you see the previous data , or even in the UI the previous data is displayed? – Rohan Agarwal Jul 11 '20 at 08:26
  • @RohanAgarwal just the console. when i select the new option, the select value does in fact change on the UI. but this does mean i'll run into problems later on when the ui _says_ it's doing one thing when it's actually doing another backend. – GROVER. Jul 11 '20 at 08:26
  • Does this answer your question? [React setState not Updating Immediately](https://stackoverflow.com/questions/38558200/react-setstate-not-updating-immediately) This question is asked several times/week. Please try to search before posting question. – Drew Reese Jul 11 '20 at 08:51

1 Answers1

7

setState operations are async in nature. So whenever a setState op is done, its not guaranteed that the updated value of state will be available just after the setState statement

From React Doc

React may batch multiple setState() calls into a single update for performance.

Because this.props and this.state may be updated asynchronously, you should not rely on their values for calculating the next state.

Now, if you want to use the new state value, you should store the value, in this case the data, in a variable, set your state, but use the variable to perform other operation inside the function, like calling API,etc.

Edit (As pointed out by @Grover):

setState also provides a second argument which is a callback that gets fired after the update operation takes place. One can get the updated state value in it and can use this to perform operations with the updated values.

this.setState({foo: 'bar'}, () => { 
    // actions
});

However, the React Doc suggests using componentDidUpdate instead of setState callback. This answer tries to explain it why: What is the advantage of using componentDidUpdate over the setState callback?

Rohan Agarwal
  • 2,441
  • 2
  • 18
  • 35