Push() method in React + Redux

Hey there,

This is a code I was trying to run for one of the React + Redux challenges:

class DisplayMessages extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      input: '',
      messages: []
    }
     this.handleChange = this.handleChange.bind(this);
     this.submitMessage = this.submitMessage.bind(this);
  }
  // Add handleChange() and submitMessage() methods here

  handleChange(event) {
    this.setState({
      input: event.target.value
    });
  };

  submitMessage() {
    console.log(this.state.input)
    this.setState({
      messages: this.state.messages.push(this.state.input),
      input: ""
    });
  };

  render() {
    return (
      <div>
        <h2>Type in a new Message:</h2>
        { /* Render an input, button, and ul below this line */ }
        <input onChange={this.handleChange} value={this.state.input}></input>
        <button onClick={this.submitMessage}>Submit</button>
        <ul>{this.state.messages.map(elem => <li>{elem}</li>)}</ul>
        {console.log(this.state)}
        { /* Change code above this line */ }
      </div>
    );
  }
};

Weirdly, in the submitChange() action, when I push the data from this.state.input to this.state.messages (an empty array), it returns messages: 1 instead of [ this.state.input ]. This surprises me because I expect push() to behave as it does in JavaScript. Is that something to do with immutability in state? Why returning 1 though?

Hi, @InTheMood

.push doesn’t create a new array but just mutate the data.
From the docs: The push() method adds one or more elements to the end of an array and returns the new length of the array.

You can use .concat method or […this.state.messages, this.state.input]

Great, that’s what I was thinking. But how to explain the weird React behaviour of changing the empty array to an integer that counts how many element I pushed inside? That still surprises me, because even if I did mutate the data, I’m expecting to see the array the same way I would in JavaScript.

This isn’t “weird React behavior”, it is in fact behaving “as it does in JavaScript”. This is JavsScript.

When you do:

    this.setState({
      messages: this.state.messages.push(this.state.input),
      input: ""
    });

First it evaluates this.state.messages.push(this.state.input). As mentioned, this is a big no-no in React, mutating the state directly. But OK, but the return value from push is the size of the new array. If it was empty, it is now 1. Then you are telling to to put that into state:

    this.setState({
      messages: 1,
      input: ""
    });

So, you mutated that state variable and then immediately overwrote it with a number. This is JS behavior. It may be an unfamiliar pattern, but it is 100% JS.

Ah damn now it makes sense! I should’ve just read again the documentation on .push(), I was intuitively thinking that it would return the array with the element added, not the length.

Great, thank you :slight_smile:

Yeah, I’m made that mistake a few times. I am always checking the docs for return values for those things and to see if they mutate the original. Of course, this does mutate the original so we shouldn’t use it on data that is expected to be immutable. Usually I would use the spread operator here, or maybe the concat method.