Manage State Locally First (React Redux examples)

Manage State Locally First (React Redux examples)
0

#1

Tell us what’s happening:

Not passing any tests. Not sure what I’m missing.

Your code so far


class DisplayMessages extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      input: '',
      messages: []
    }
  }

  handleChange = (e) => {
    this.setState({ input: e.target.value })
  }

  submitMessage = () => {
    this.setState(prevState => ({
      input: "",
      messages: [...prevState.messages, prevState.input]
    }))
  }
  // add handleChange() and submitMessage() methods here

  render() {
    return (
      <div>
        <h2>Type in a new Message:</h2>
        { /* render an input, button, and ul here */ }
        <input type="text" onChange={this.handleChange} value={this.state.input} />
        <button type="button" onClick={this.submitMessage}>Add message</button>
        <ul>
         {this.state.messages.map(msg => (
           <li>{msg}</li>
         ))}
        </ul>
        { /* change code above this line */ }
      </div>
    );
  }
};

Your browser information:

User Agent is: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2) AppleWebKit/604.4.7 (KHTML, like Gecko) Version/11.0.2 Safari/604.4.7.

Link to the challenge:
https://learn.freecodecamp.org/front-end-libraries/react-and-redux/manage-state-locally-first


#2

OK, some thoughts:

I wasn’t able to get your arrow function class members to work. That looks like the right way to do it, but it looks like whatever transpiler is being used can’t handle them. AFAIK, that is a fairly new suggestion and may or may not be officially part of JS. In any case, it appears that it is not handled by the the testing rig. Just use regular functions. Maybe someone smarter than me can get them to work, but when I try to use arrow functions are class members, I get all kinds of errors in the browser console.

Of course, then you’re going to have to bind this to those functions. A popular way is to put a line like:

this.functionName = this.functionName.bind(this)

at the bottom of your constructor.

In your code:

  submitMessage = () => {
    this.setState(prevState => ({
      input: "",
      messages: [...prevState.messages, prevState.input]
    }))
  }

you are treating this.setState as if it were taking a callback. For it’s first parameter, it accepts an object, with the properties you want changed. For example, if I wanted to change the input to “gorilla”, I would:

this.setState({ input: "gorilla })

You are correct that you need to act on a copy of state and not state itself. There are two ways to do this: 1) copy state into a new object, make the changes, then give it to setState, or 2) create the new object in situ, as you send the object, like I did in the above example.

When I make those adjustments to your code, it passes.

Please let us know if I didn’t explain something well enough.


#3

Thanks for the in-depth response @kevinSmith!

You’re right, it looks like this is not part of the language yet.

FWIW, this still works:

  handleChange(e) {
    this.setState(() => ({ input: e.target.value }))
  }

  submitMessage() {
    this.setState(({messages, input}) => ({ 
      input: "",
      messages: [...messages, input]
    }))
  }

Using another “form” (or type signature?) for setState that accepts a function as argument. In the docs here.
Thanks again!
Cheers


#4

You’re right, it looks like this is not part of the language yet.

No, but I think there are some transpilers that accept that.

Using another “form” (or type signature?) for setState that accepts a function as argument. In the docs here.

That’s a good point, I’d forgotten all about that.


#5

Hi, thi is my solution, hope it helps:

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)
  }

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

submitMessage(){
  this.setState(({messages})=>({messages:messages.concat(this.state.input)}))
  this.setState({input:""})
}

  render() {
    return (
      <div>
        <h2>Type in a new Message:</h2>
          <input
          onChange={this.handleChange}
          value={this.state.input}
          ></input>
          <button 
          onClick={this.submitMessage}>
          </button>
          <ul>
          {this.state.messages.map(message=>
          (<li>{message}</li>)
          )}
          </ul>
      </div>
    );
  }
};

#6

thanks for the solution, it passes! however, i don;t understand why you had to set messages the way you did instead of how i supposed like so:

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