Manage State Locally First Task

Tell us what’s happening:
My code doesn’t pass tests. I figured out that the cause is the submitMessage function. Why doesn’t my code pass tests with the push function? As I understand I don’t change the state directly.

Your code so far

class DisplayMessages extends React.Component {
  constructor(props) {
    this.state = {
      input: '',
      messages: []
    this.handleChange = this.handleChange.bind(this);
    this.submitMessage = this.submitMessage.bind(this);
  handleChange(event) {
    let newMessages = this.state.messages;
      messages : newMessages,
      input: ""
  // add handleChange() and submitMessage() methods here

  render() {

    return (
        <h2>Type in a new Message:</h2>
        { /* render an input, button, and ul here */ }
        <input onChange={this.handleChange} value={this.state.input} />
        <button onClick = {this.submitMessage}>Submit</button>
, index) {
            return <li key={index}>{ind}</li>
        { /* change code above this line */ }

Your browser information:

User Agent is: Chrome/71.0.3578.98.

Link to the challenge:

rather than push to your state, try using the spread operator like this:

      messages : [...this.state.messages, this.state.input],
      input: ""

not sure if it will work but its my go-to method :slight_smile:

good luck!

1 Like

I just noticed you weren’t actually pushing to state (awesome!)

sometimes react is just confusing - I’m not 100% sure why your method doesn’t work sorry

edit: I think it’s just the test script not liking your solution even though it works - though it is a bit more convoluted than just using the spread operator

Yes, spread operator works, I just don’t understand why the push doesn’t work.
I mean, the push doesn’t pass tests

If you want to learn it yourself (just like me!) try the following in your browser console.

const arr1 = ['cat', 'dog', 'wolf'];
const arr2 = arr1;

We have defined arr1 and defined arr2.

If you console log this: console.log(arr2) , you would see ['cat', 'dog', 'wolf'] in the console.

All of the above makes sense until now.

Now the fun part. Change the first element of arr2 to say, ‘big cat’ like so:

arr2[0] = 'big cat';

Now again, console log arr2 and you will see the following printed ['big cat', 'dog', 'wolf'];.

Seems right? NO! It looks fine, but you also have changed the arr1.
Try console logging arr1 and see the result.

Surprised? We never changed arr1 but it also contains ‘big cat’.

The reason it happened because when you do this:

const arr1 = ['cat', 'dog', 'wolf'];
const arr2 = arr1;

You are creating a NEW array arr1.
Then you are creating a new constant arr2 that POINTS towards arr1 in the memory.
So, in essence, you never created a new array named arr2, but you only created a new constant that points to an existing array.

This is exactly what you’re having the issue in the above code.

let newMessages = this.state.messages;

newMessages is not a brand new array, it only points towards this.state.messages and pushing the item directly into the state (i.e mutating state directly) is not possible in React.

While doing this:

[...this.state.messages, this.state.input]

means you’re taking the state,messages array, spreading it into a NEW array, adding a new element, and assigning it to the state, which is acceptable.

Another possible method is using slice (because slice returns a new array):

const newMessages = this.state.messages.slice();

and now you can use newMessages.push(newValue), and it would work fine.

Although I suggest that you should stick with the ES6 spread operator syntax.


Oh, now I understand, thank you very much, your post was very helpful.

Great answer - thank you