Use Array.map() to Dynamically Render Elements

Tell us what’s happening:
This code works as it should but I am still failing the test. I don’t understand why.

Your code so far


const textAreaStyles = {
  width: 235,
  margin: 5
};

class MyToDoList extends React.Component {
  constructor(props) {
    super(props);
    // change code below this line
this.state = {
  userInput: '',
  toDoList: []
};
    // change code above this line
    this.handleSubmit = this.handleSubmit.bind(this);
    this.handleChange = this.handleChange.bind(this);
  }
  handleSubmit() {
    const itemsArray = this.state.userInput.split(',');
    this.setState({
      toDoList: itemsArray
    });
  }
  handleChange(e) {
    this.setState({
      userInput: e.target.value
    });
  }
  render() {
    const items = this.state.toDoList.map(function(item){
      return <li> {item} </li>;
    });
    return (
      <div>
        <textarea
          onChange={this.handleChange}
          value={this.state.userInput}
          style={textAreaStyles}
          placeholder="Separate Items With Commas" /><br />
        <button onClick={this.handleSubmit}>Create List</button>
        <h1>My "To Do" List:</h1>
        <ul>
          {items}
        </ul>
      </div>
    );
  }
};

Your browser information:

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

Link to the challenge:
https://learn.freecodecamp.org/front-end-libraries/react/use-array-map-to-dynamically-render-elements

      return <li> {item} </li>;

For some reason, the spaces before and after {item} are confusing the test.

4 Likes

Why does this line not run into JavaScript error? i mean when we are writing js directly in render() before returning then shouldn’t js rules be applied as well hence instead of writing <li>{item}</li> shouldn’t we return a string "<li>{item}</li>". i think i have overlooked some concept here.

Because it’s not JS, it’s JSX. This:

<li>{item}</li>

is a combination of html and injected JS called JSX. React converts it to the necessary html and JS. It is being used in a JS environment, but it is not JS yet.

If we run this code:

class Test extends React.Component {
  render() {
    const value = 'howdy'
    const jsxElement = <p>{value}</p> 
    console.log(jsxElement)
    return (
      <div>
        {jsxElement} 
      </div>
    )
  }
}

We see this in the console:

{$$typeof: Symbol(react.element), type: “p”, key: null, ref: null, props: {…}, …}
$$typeof: Symbol(react.element)
key: null
props: {children: “howdy”}
ref: null
type: “p”
_owner: p {_currentElement: {…}, _rootNodeID: 0, _compositeType: 0, _instance: Test, _hostParent: null, …}
proto: Object

And if we inspect the DOM, we see

<div data-reactroot=""><p>howdy</p></div>

So we see that a transformation has taken place. That is what React is doing for us behind the scenes.

Try to remember that JSX is not HTML and and it is not JS. It looks like HTML with JS injected and React will do what is needed to convert it into something the browser can read.

We are used to putting JSX in the return of the render method but it can also be stored in variables, arrays, passed as parameters, etc.

Here is a pen with which you can see this.

3 Likes

Why can’t we use arrow function?
i.e instead of this:-

const items = this.state.toDoList.map(function(item){
      return <li> {item} </li>;
    });

this:-

const items =this.state.toDoList.map((item) => {
       <li>{item}</li>
     });

Thank You, Sir, I got it

you should add a return keyword in the curly brackets

const items = this.state.toDoList.map(item => {
     return <li>{item}</li>;
});

I’m still a bit confused here. Is the entire component a JSX element? Why in some places can we write pure JS and in other places we have to encapsulate our JS in curly braces?

For the example above, I would think the entire JS statement would need to encased in curly braces for it to run. And, since it is not, seems like we should just be able to do the following:

this.state.toDoList.map((item) => {return <li>item</li>})

Is the whole component JSX and does the compiler just scan for any html (inside the render function or not) and it will allow it? Also, once it finds some html, it requires curly braces for any JS input?

Is the entire component a JSX element

Think of anything that looks HTML-ish in React as a JSX element. It’s not HTML of course, it’s JSX. But it does certainly look HTML-ish and can roughly translate to HTML in the end, translated by React.

Why in some places can we write pure JS …

Because React is JS. You are doing JS.

…and in other places we have to encapsulate our JS in curly braces?

Because at that point you are injecting JS into JSX. You are in a JS function, but you are returning/rendering some JSX and you want to inject some JS inside it to have some of the dynamic data in the JSX.

this.state.toDoList.map((item) => {return <li>item</li>})

should be:

this.state.toDoList.map((item) => {return <li>{ item }</li>})

This is JS. Everything is JS, except, you have a JSX element <li>{ item }</li>. React sits up and says, “Wait a minute JS, there is some JSX here and you don’t know what that is. Don’t worry, I’ll translate it to some JS for you and I’ll do it behind the scenes so you or the programmer don’t have to even know it’s happening.” So React takes a look at <li>{ item }</li> and says, “OK, I know an li is just an HTML element, I’ll translate that into some JS so JS can output it properly. But that { item } is in curly braces. So, the coder doesn’t want the string “item”, they want me to find the variable item back in JS land and insert it here.”

If you had <li>item</li>, it would just say “item”. But if you have <li>{ item }</li>, it will show whatever the variable item refers to.

Don’t worry. A few years ago, I was struggling to understand that. Now I’m a professional React Native developer. Just keep at it. There is a lot that is very confusing about this. It is a different way of thinking. But if you keep at it, you will get it. And in the end, it can be incredibly powerful.

Just for emphasis, from your last paragraph:

Is the whole component JSX …

No, just the stuff that looks HTML-ish. Technically you can do React without JSX, but wouldn’t advise it. The component is JS, which may contain some JSX.

… and does the compiler just scan for any html …

My knowledge is a little weaker here, but I think it is the React library that is doing that …

(inside the render function or not)

JSX will usually be in the render or in a function that get’s called in render or a variable that gets injected into JSX (those curly braces) inside render. That is what they mean by “render”.

Also, once it finds some html, it requires curly braces for any JS input?

Essentially. You can have JSX without any dynamic content and you wouldn’t need any curly braces. That is fine. For example, if I just wanted a static header:

class Header extends Component {
  render() {
    return (
      <h1>Welcome to the world's greatest app!!!</h1>
    );
  };
};

That (<h1>Welcome to the world's greatest app!!!</h1>) is JSX and has no curly braces because there is no dynamic content, just some static text. But if I wanted to inject some dynamic content, imagine that the username is being sent to the header component.

class Header extends Component {
  render() {
    return (
      <h1>Welcome { this.props.username }, to the world's greatest app!!!</h1>
    );
  };
};

Now I need curly braces because it is injecting JS into the JSX. The variable this.props.username comes from JS land. That is essentially what makes JSX special - otherwise it would basically be HTML. (That and the fact that you can create your own components.)

2 Likes

@cjbechtl, thanks for posting this question and everyone for your in depth responses.

The code you submitted was correct, but our tests were a little too brittle as @kevinSmith mentioned. This issue was fixed with https://github.com/freeCodeCamp/freeCodeCamp/pull/39581 and the code above should pass.