Array Mapping in React Redux: Manage State Locally First

Why I cannot map outside of the ul like this:

  render() {
    const messages = (this.state.messages).map((message) => <li>{message}</li>)
    return (
      <div>
        <h2>Type in a new Message:</h2>
        { /* Render an input, button, and ul below this line */ }
        <input type="text" value={this.state.input} onChange={this.handleChange} />
        <button type="submit" onClick={this.handleSubmit}>Add message</button>
        <ul>{messages}</ul>

and have to do map inside the ul like this:

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

in order to pass the test spec, despite the same expected result? Is it because the second approach is best practice? or anything? Thanks!

Tell us what’s happening:
Describe your issue in detail here.

  **Your code so far**

class DisplayMessages extends React.Component {
constructor(props) {
  super(props);
  this.state = {
    input: '',
    messages: []
  }
  this.handleChange = this.handleChange.bind(this);
  this.handleSubmit = this.handleSubmit.bind(this);
}
// Add handleChange() and submitMessage() methods here
handleChange(event) {
  this.setState({
    input: event.target.value,
    message: this.state.messages // yea, we need this to preserve the whole original state that has not been changed in the new state.
  })
}

handleSubmit(event) {
  const messagesArray = this.state.messages.concat([this.state.input]);
  this.setState({
    input: '',
    messages: messagesArray
  })
}

render() {
  const messages = (this.state.messages).map((message) => <li>{message}</li>)
  return (
    <div>
      <h2>Type in a new Message:</h2>
      { /* Render an input, button, and ul below this line */ }
      <input type="text" value={this.state.input} onChange={this.handleChange} />
      <button type="submit" onClick={this.handleSubmit}>Add message</button>
      <ul>{messages}</ul>
      { /* Change code above this line */ }
    </div>
  );
}
};
  **Your browser information:**

User Agent is: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36

Challenge: Manage State Locally First

Link to the challenge:

const messages = (this.state.messages).map((message) => <li>{message}</li>)

Why is this.state.messages in parentheses? When I remove those, your code passes for me. I assume that the test is searching for the string “this.state.messages.map(”. There’s nothing wrong with putting those parentheses there, except that there is no reason to so it might cause confusion.

Is storing it in a variable like you’ve done better or worse than putting it directly in the JSX?

I actually prefer what you’ve done, but I don’t mind putting it in the JSX if it is short. For this example, I would probably put it in the JSX since it is so small, but I wouldn’t complain about what you’ve done. The inline version could be shortened further by using an implicit return. And even more if it was it’s own component (so you could just give the component and not a function literal). But that’s nitpicky stuff and probably not important here.

1 Like

Ooh! Nice! Thank you! I did not try that.
I always put parentheses for grouping, in the effort to control the flow, to make sure that the one in parentheses is evaluated first before moving right down the line. Beside the grouping makes it easier for me to read and separate one ‘object’ from the other.

I don’t quite like golf coding, just in case I have to revisit it in the future it won’t be so difficult for me to understand my thought process.

Thanks!

You don’t need to do that. With chained properties and methods, it knows to work from left to right. I understand what you are thinking, but that is the kind of thing that other developers see as odd and unnecessary, and/or showing a lack of knowledge about how JS works.

I don’t quite like golf coding, just in case I have to revisit it in the future it won’t be so difficult for me to understand my thought process.

Yeah, I get that. But “difficult to understand” is relative. I understand the desire to break things apart for readability - in fact I think it is really important. But no experienced JS coder is going to be confused by:

const messages = this.state.messages.map((message) => <li>{message}</li>)

If I needed to break it up, my first thought would be to break out the callback function:

const messages = this.state.messages.map(renderMessageListItem)

or just make a small functional component:

const messages = this.state.messages.map(MessageListItem)

and at that point it is small enough to put in your JSX. Or, you could break that and the ul out into their own component, MessageList. If the code gets complicated, that is probably the best solution, going with React’s strengths. (But this wasn’t an option here, in this challenge.)

But inventing some uncommon notation - I don’t think that is a good longterm solution. At least not if you want to work with other coders.

1 Like

Thanks so much! They all make sense. Yea, I’ll do that!

1 Like