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


#7

hey maybe got the answer but correct me if I am wrong
there is two problem in this code
1 . You didn’t bind the method.
2.In submitMessage method when you were setting the state of messages you were taking a argument which was not passed when button triggered so it is unknown (prevState).Instead of prevState you could use

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

it would solve the problem.


#8

That’s correct, I was using (or trying to use) the class field syntax to avoid explicit binding. This is not yet available in browsers but usually made possible by a Babel transpile step.

prevState definitely works, I posted a link to the relevant part of the docs that goes over the function form of setState, but I’ll re-post below along with the answer I arrived at.

Just to be 100% clear: my problem was resolved last June (hopefully this thread should appear as answered, specifically by the second post by Kevin above), by converting from class field syntax that I originally had (currently a stage 3 proposal which is not yet supported in browsers) to regular class methods. You can read more about the proposal here: https://github.com/tc39/proposal-class-fields. The relevant part of the React docs on how setState is being used here: https://reactjs.org/docs/state-and-lifecycle.html#state-updates-may-be-asynchronous.