Saxtheowl
Saxtheowl

Reputation: 4658

Understanding state input in react

I have a method submitMessage that is supposed to concatenate the current message that has been stored in my input state and then clear it:

submitMessage() {
  this.setState({
    input: '',
    messages : [...this.state.messages, this.state.input]
  });
}

The method is working as intended and the whole app too, what I don't understand is why input can be cleared before the concatenate, is input and this.state.input not in the same place in memory ?

Here is my full code:

class DisplayMessages extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      input: '',
      messages: []
    }    
  }
  handleChange(event) {
    this.setState({
      input: event.target.value,
      messages: this.state.messages
      })
  }
  submitMessage() {
    this.setState({
      input: '',
    messages : [...this.state.messages, this.state.input]
    })
  }
  render() {
    return (
      <div>
        <h2>Type in a new Message:</h2>
        <input onChange={this.handleChange.bind(this)} value={this.state.input} />
        <button onClick={this.submitMessage.bind(this)}>Submit</button>
        <ul>{this.state.messages.map((item) => {
            return <li key={item + 1}>{item}</li>
          })}
        </ul>
      </div>
    );
  }
};

Upvotes: 0

Views: 269

Answers (1)

Drew Reese
Drew Reese

Reputation: 202618

Why are <input /> and this.state.input not in the same place in memory?

input is an html DOM element, while the other, this.state.input is a javascript object, they are two completely different things. The only thing relating the two is the JSX syntax and react framework.

Why can input be cleared before the message concatenation?

In react, state and props are treated as immutable objects, and react state works between render cycles. All state updates within any single cycle are queued up and batch processed for the next render cycle. Setting this.state.input to an empty string and appending it to the this.state.messages array are queued to to be processed for the next rendered view.

The following are all equivalent in terms of next computed state:

this.setState({
  input: '',
  messages: [...this.state.messages, this.state.input],
});

and

this.setState({
  messages: [...this.state.messages, this.state.input],
  input: '',
});

and

this.setState({ input: '' });
this.setState({
  messages: [...this.state.messages, this.state.input],
});

and even

this.setState({ input: '' });
this.setState({
  messages: [...this.state.messages, this.state.input],
});
this.setState({
  messages: [...this.state.messages, this.state.input],
});

The last one you may find surprising (what!?), but recall that state state is immutable and batch processed, so in the case of updating messages, this.state.messages and this.state.input have the same values in both calls, and thus, the last one invoked is what sets state. BTW, (and outside the scope of this question), functional state updates help solve the issue with this last example.

Upvotes: 1

Related Questions