0
votes

I am sending state value from parent component to child component as props, but I child component updates before the parent component's state is set.

This is in the parent component

  handleSubmit = function(e){
              e.preventDefault();
            this.setState({table: true});
            this.setState({rows: [
              {
                id: 1,
                name: this.state.name,
                email: this.state.email,
                phone: this.state.phone
              }
            ]
          } , () => {console.log(this.state.rows)});
            this.setState({updateInTable: true} , () => {console.log(this.state.updateInTable)})
            this.setState({submit: false});
          }

This is in the child component

  componentDidUpdate() {
          console.log('From table '+this.props.updateInTable);
          if(this.props.updateInTable){
            console.log('Coming from table '+this.props.rows);
          }
        }

I am sending these as props

           <Table
                 table={this.state.table}
                 name={this.state.name}
                 rows={this.state.rows}
                 updateInTable={this.state.updateInTable}
                 />

These are returning from console

From table false

From table true

Coming from table [object Object]

[Object]

true


I expect [Object], true which are in parent component to be printed first and then From table false , From table true


CodePen Link: https://codepen.io/anon/pen/ZXOrPE

3

3 Answers

0
votes

It is not guaranteed that when you change the children component are updated immediately. In fact updates are usually batched for performance.

Calling setState multiple times in a row in the same function is considered sort of a bad practice, you can/should actually group the whole process in one setState call

0
votes

Expanding upon what Mario F answered, the React documentation does in fact state:

setState() does not always immediately update the component. It may batch or defer the update until later. This makes reading this.state right after calling setState() a potential pitfall.

Instead, try setting your state in a single call...

handleSubmit = function(e) {
  e.preventDefault();

  this.setState({
    table: true,
    rows: [{
      id: 1,
      name: this.state.name,
      email: this.state.email,
      phone: this.state.phone
    }],
    updateInTable: true,
    submit: false
  });
}

If you do in fact need the state to update synchronously, consider using componentDidUpdate or a setState callback, which are guaranteed to fire after the update has been applied as described in the documentation provided.

0
votes

Adding to what Mario F and T Porter said, multiple setState are batched in React. Multiple setStates should be combined to one. But in your case even if we combine multiple setState into one output remains same. That is because componentDidUpdate() method in child component is called twice onSubmit.

onClick Submit button two functions are called in following order:

  • submitClick = function(){ this.setState({ cancel: false}); }

When submitClick is called componentDidUpdate() is called for the first time and From table false is logged as this.props.updateInTable is false at this time.

  • handleSubmit (when the submit event bubbled to form)

When handleSubmit is called multiple setStates are batched and componentDidUpdate() is called again and at this time this.props.updateInTable is true. Therefore, the output logged is:

From table true

Coming from table [object Object]

The setState callbacks are always executed after lifecycle of child component is done, that is why folowing is consoled last.

[Object]

true

I hope it answers your question.