Meet JSX...Again!

by kirupa   |   29 September 2017

As you probably noticed by now, we've been using a lot of JSX in the previous tutorials. What we really haven't done is taken a good look at what JSX actually is. How does it actually work? Why do we not just call it HTML? What quirks does it have up its sleeve? In this tutorial, we'll answer all of those questions and more! We will do some serious backtracking (and some forwardtracking!) to get a deeper look at what we need to know about JSX in order to be dangerous.

Onwards!

OMG! A React Book Written by Kirupa?!!

To kick your React skills up a few notches, everything you see here and more (with all its casual clarity!) is available in both paperback and digital editions.

BUY ON AMAZON

What Happens with JSX?

One of the biggest thing we've glossed over is trying to figure out what happens with our JSX after we've written it. How does it end up as HTML that we see in our browser? Take a look at the following example where we define a component called Card:

class Card extends React.Component {
  render() {
    var cardStyle = {
      height: 200,
      width: 150,
      padding: 0,
      backgroundColor: "#FFF",
      WebkitFilter: "drop-shadow(0px 0px 5px #666)",
      filter: "drop-shadow(0px 0px 5px #666)"
    };
    
    return React.createElement(
      "div",
      { style: cardStyle },
      React.createElement(Square, { color: this.props.color }),
      React.createElement(Label, { color: this.props.color })
    );
  }
};

We can quickly spot the JSX here. It is the following four lines:

<div style={cardStyle}>
  <Square color={this.props.color}/>
  <Label color={this.props.color}/>
</div>

The thing to keep in mind is that our browsers have no idea what to do with JSX. They probably think you are crazy if you ever even try to describe JSX to them. That is why we have been relying on things like Babel to turn that JSX into something the browsers understand: JavaScript.

What this means is that the JSX we write is for human (and well-trained cats) eyes only. When this JSX reaches our browser, it ends up getting turned into pure JavaScript:

return React.createElement(
  "div",
  { style: cardStyle },
  React.createElement(Square, { color: this.props.color }),
  React.createElement(Label, { color: this.props.color })
);

All of those neatly nested HTML-like elements, their attributes, and their children all get turned into a series of createElement calls with default initialization values. Here is what our entire Card component looks like when it gets turned into JavaScript:

class Card extends React.Component {
  render() {
    var cardStyle = {
      height: 200,
      width: 150,
      padding: 0,
      backgroundColor: "#FFF",
      WebkitFilter: "drop-shadow(0px 0px 5px #666)",
      filter: "drop-shadow(0px 0px 5px #666)"
    };
    
    return React.createElement(
      "div",
      { style: cardStyle },
      React.createElement(Square, { color: this.props.color }),
      React.createElement(Label, { color: this.props.color })
    );
  }
};

Notice that there is no trace of JSX anywhere! All of these changes between what you wrote and what our browser sees is part of the transpiling step we've talked about in the Building Your First React App tutorial. That transpilation is something that happens entirely behind-the-scenes thanks to Babel where we've been using it to perform this JSX->JS transformation entirely in the browser. We'll eventually look at using Babel as part of a more-involved build environment where we will just generate a transformed JS file, but more on that when we get there in the future.

But yeah, there you have it. An answer to what exactly happens to all of our JSX. It gets turned into sweet SWEET JavaScript.

JSX Quirks to Remember

As we've been working with JSX, you probably noticed that we ran into some arbitrary rules and exceptions on what you can and can't do. In this section, let's put many of those quirks together in one area and maybe even run into some brand new ones!

Evaluating Expressions

JSX is treated like JavaScript. As you've seen a few times already, this means that you aren't limited to dealing with static content like the following:

class Stuff extends React.Component {
  render() {
    return (
      <h1>Boring static content!</h1>
    );
  }
};

The values you return can be dynamically generated. All you have to do is wrap your expression into curly braces:

class Stuff extends React.Component {
  render() {
    return (
      <h1>Boring {Math.random() * 100} content!</h1>
    );
  }
};

Notice that we are throwing in a Math.random() call to generate a random number. It gets evaluated along with the static text alongside it, but because of the curly braces, what you see will look something like the following: Boring 28.6388820148227 content!

These curly braces allow your app to first evaluate the expression and then return the result of the evaluation. Without them, what you would see would be your expression returned as text: Boring Math.random() * 100 content!

That isn't what you would probably want!

Returning Multiple Elements

In a lot of our examples, we've always returned one top-level element (often a div) that then had many other elements under it. You aren't technically limited to following that pattern. You can actually return multiple elements. There are two ways you can do that.

One way is by using an array-like syntax:

class Stuff extends React.Component {
  render() {
    return (
      [
        <p>I am</p>,
        <p>returning a list</p>,
        <p>of things!</p>
      ]
    );
  }
};

We are returning three p tags. They don't have a single common parent. Now, when you are returning multiple items, there is one detail that you may or may not have to deal with depending on the version of React you are targeting. You will need to specify a key attribute and a unique value for each item:

class Stuff extends React.Component {
  render() {
    return (
      [
        <p key="1">I am</p>,
        <p key="2">returning a list</p>,
        <p key="3">of things!</p>
      ]
    );
  }
};

This helps React better understand which element it is dealing with and whether to make any changes to it or not. How will you know whether you need to add the key attribute or not? React will tell you! You will see a message similar to to following printed to your Dev Tools Console: Warning: Each child in an array or iterator should have a unique "key" prop.

Besides the array-like approach, you have another (arguably better!) way of returning multiple elements. This involves something known as fragments. The way you use it looks as follows:

class Stuff extends React.Component {
  render() {
    return (
      <React.Fragment>
        <p>I am</p>
        <p>returning a list</p>
        <p>of things!</p>
      </React.Fragment>
    );
  }
};

You wrap the list of items you want to return into a magical React.Fragment component. There are a few cool things to note here:

  1. This component doesn't actually generate a DOM element. It is just something you specify in JSX that has no tangible existence when transpiled into the HTML your browser sees.
  2. You aren't treating what you are returning as items in an array. That means no commas or anything separating each item.
  3. There is no need to specify a unique key attribute and value. This is all taken care of under the covers for you.

Before we leave this section, there is a more condensed syntax you can use instead of fully specifying React.Fragment...like an animal. You can use just empty <> and </> tags:

class Stuff extends React.Component {
  render() {
    return (
      <>
        <p>I am</p>
        <p>returning a list</p>
        <p>of things!</p>
      </>
    );
  }
};

This looks like something from the future, so if you are inclined to use fragments to return multiple values, feel free to use this smaller syntax if you want.

You Can't Specify CSS Inline

As we saw in Chapter 4, the style attribute in your JSX behaves differently from the style attribute in HTML. In HTML, you can specify CSS properties directly as values on your style attribute:

<div style="font-family:Arial;font-size:24px">
	<p>Blah!</p>
</div>

In JSX, the style attribute can't contain CSS inside it. Instead, it needs to refer to an object that contains styling information instead:

class Letter extends React.Component {
  render() {
    var letterStyle = {
      padding: 10,
      margin: 10,
      backgroundColor: this.props.bgcolor,
      color: "#333",
      display: "inline-block",
      fontFamily: "monospace",
      fontSize: "32",
      textAlign: "center"
    };

    return (
      <div style={letterStyle}>
        {this.props.children}
      </div>
    );
  }
}

Notice that we have an object called letterStyle that that contains all of the CSS properties (in camel-cased JavaScript form) and their values. That object is what we then specify to the style attribute.

Comments

Just like it is a good idea to comment your HTML, CSS, and JavaScript, it is a good idea to provide comments inside your JSX as well. Specifying comments in JSX is very similar to how you would comment in JavaScript...except for one exception. If you are specifying a comment as a child of a tag, you need to wrap your comment by the { and } angle brackets to ensure it is parsed as an expression:

ReactDOM.render(
  <div className="slideIn">
    <p className="emphasis">Gabagool!</p>
    {/* I am a child comment */}
    <Label/>
  </div>,
  document.querySelector("#container")
);

Our comment in this case is a child of our div element. If you specify a comment wholly inside a tag, you can just specify your single or multi-line comment without having to use the { and } angle brackets:

ReactDOM.render(
  <div className="slideIn">
    <p className="emphasis">Gabagool!</p>
    <Label
      /* This comment
         goes across
         multiple lines */
         className="colorCard" // end of line
    />
  </div>,
  document.querySelector("#container")
);

In this snippet, you can see an example of what both multi line comments and a comment at the end of a line looks like. Now that you know all of this, you have one less excuse to not comment your JSX :P

Capitalization, HTML Elements, and Components

Capitalization is important. To represent HTML elements, ensure the HTML tag is lower-cased:

ReactDOM.render(
  <div>
    <section>
      <p>Something goes here!</p>
    </section>
  </div>,
  document.querySelector("#container")
);

When wishing to represent components, the component name must be capitalized:

ReactDOM.render(
  <div>
    <MyCustomComponent/>
  </div>,
  document.querySelector("#container")
);	  

If you get the capitalization wrong, React will not render your content properly. Trying to identify capitalization issues is probably the last thing you'll think about when things aren't working, so keep this little tip in mind.

Your JSX Can Be Anywhere

In many situations, your JSX will not be neatly arranged inside a render or returnfunction like in the examples we've seen so far. Take a look at the following example:

var swatchComponent = <Swatch color="#2F004F"></Swatch>;

ReactDOM.render(
  <div>
    {swatchComponent}
  </div>,
  document.querySelector("#container")
);	  

We have a variable called swatchComponent that is initialized to a line of JSX. When our swatchComponent variable is placed inside the render function, our Swatch component gets initialized. All of this is totally valid, and we will do more such things in the future when we learn how to generate and manipulate JSX using JavaScript.

Conclusion

With this tutorial, we've finally pieced together the various bits of JSX information that the previous tutorials introduced into one location. The most important thing to remember is that JSX is not HTML. It looks like HTML and behaves like it in many common scenarios, but it is ultimately designed to be translated into JavaScript. This means you can do things that you could never imagine doing using just plain HTML. Being able to evaluate expressions or programmatically manipulate entire chunks of JSX is just the beginning. In future tutorials, we'll explore this intersection of JavaScript and JSX further.

Next tutorial: Dealing with State

If you have a question about this or any other topic, the easiest thing is to drop by our forums where a bunch of the friendliest people you'll ever run into will be happy to help you out!

THE KIRUPA NEWSLETTER

Get cool tips, tricks, selfies, and more...personally hand-delivered to your inbox!

( View past issues for an idea of what you've been missing out on all this time! )

GOT A QUESTION?

HOT FORUM TOPICS

Serving you freshly baked content since 1998!

Killer hosting by (mt) mediatemple

Facebook Twitter Youtube Pinterest Instagram Github
BACK TO TOP
new books - yay!!!