DEV Community

Felipe Galvão
Felipe Galvão

Posted on • Updated on • Originally published at felipegalvao.com.br

Learn React - Part 2 - Getting to know JSX

Originally published on my blog

In our last post about React, we created a React project using Webpack, with some nice features. Now, we will explore JSX a little bit. JSX is a syntax extension for Javascript that is widely used with React applications.

This post is part of a series of posts where I go through the basics of React:

  1. Simple setup for a React application with Webpack 4 (+ CSS / SASS)
  2. Getting to know JSX

With JSX, you can write Javascript code that is really similar to HTML, making it easy to develop the front-end on your web applications. Let's see some stuff that you can do with JSX.

Let's start with what we had on our last post. Click here to take a look, and you can find the link for the Github repository that you can clone and follow.

Basic features

Just so we are all on the same page, we start with this pretty basic React code:

import React from "react";
import ReactDOM from "react-dom";

const Index = () => {
  return <div>Hello React!</div>;
};

ReactDOM.render(<Index />, document.getElementById("index"));
Enter fullscreen mode Exit fullscreen mode

In the code above, when we return the div element inside of the function, we are already using JSX.

The first thing we are going to do is include a variable value in the element that is being returned. The most basic way of doing this is including the name of the variable inside of curly braces ({ }). Let's see:

import React from "react";
import ReactDOM from "react-dom";

const name = "Felipe";

const Index = () => {
  return <div>Hello { name }!</div>;
};

ReactDOM.render(<Index />, document.getElementById("index"));
Enter fullscreen mode Exit fullscreen mode

First, we define the name variable, and then include it in the element. When you access your application, you can see that the variable value is inside the div element.

We can also call a pre-defined function:

import React from "react";
import ReactDOM from "react-dom";

const name = "Felipe";

function yellName(nameToYell) {
  return nameToYell.toUpperCase();
}

const Index = () => {
  return <div>Hello { yellName(name) }!</div>;
};

ReactDOM.render(<Index />, document.getElementById("index"));
Enter fullscreen mode Exit fullscreen mode

When you refresh your browser, you will notice that the function was called, and all the characters in the name variable are now in upper case.

There are also some limitations

Now, for a change, let's see a limitation in JSX. Try to add a new paragraph right after the div that we currently have. Your code will be like this:

import React from "react";
import ReactDOM from "react-dom";

const name = "Felipe";

function yellName(nameToYell) {
  return nameToYell.toUpperCase();
}

const Index = () => {
  return <div>Hello { yellName(name) }!</div> <p>Here, a paragraph!</p>;
};

ReactDOM.render(<Index />, document.getElementById("index"));
Enter fullscreen mode Exit fullscreen mode

Well, if you refresh your browser window, you will notice that nothing is renderized. If you check the browser's console or the terminal where your Webpack server is being run, you can see the following error message: SyntaxError: Adjacent JSX elements must be wrapped in an enclosing tag.

The message is pretty clear. When you want to return 2 JSX elements, you need to enclose them in a single tag. The function that defines what will be renderized must always return one external element. Inside of it, you can have as many elements as you want, but there should be only one outer element.

Before React 16 release, the way to handle this was to put all the elements inside a div. Your code would be like this:

import React from "react";
import ReactDOM from "react-dom";

const name = "Felipe";

function yellName(nameToYell) {
  return nameToYell.toUpperCase();
}

const Index = () => {
  return (
    <div>
      <div>Hello { yellName(name) }!</div>
      <p>Here, a paragraph!</p>
    </div>
  );
};

ReactDOM.render(<Index />, document.getElementById("index"));
Enter fullscreen mode Exit fullscreen mode

Now, with the div containing the 2 elements, your application will be renderized and the 2 elements will be shown correctly. Note that you also do not need to have everything in a single line. You can break the element into several lines for better organization and readability.

With React 16 (which you should be using if you followed our last React post), you can return a list of elements. And then, your code will be like this:

import React from "react";
import ReactDOM from "react-dom";

const name = "Felipe";

function yellName(nameToYell) {
  return nameToYell.toUpperCase();
}

const Index = () => {
  return [
    <div>Hello { yellName(name) }!</div>,
    <p>Here, a paragraph!</p>
  ];
};

ReactDOM.render(<Index />, document.getElementById("index"));
Enter fullscreen mode Exit fullscreen mode

Now, when you refresh your browser, you will notice that your application will continue working in the same way. In my opinion, the list is better looking, and you don't have to create HTML elements that wouldn't be there if it wasn't to satisfy React's rule. But feel free to use the way you prefer.

Control and repetition structures

Continuing with the Javascript with HTML, it's possible to use control and repetition structures. Conditional rendering, for example, can be achieved using a simple if block, the one you are used to work with in standard Javascript:

import React from "react";
import ReactDOM from "react-dom";

const name = "Felipe";

function sayHello(name) {
  if (name) {
    return <p>Hello { name }!</p>;
  } else {
    return <p>Hello, nobody</p>;
  }
}

const Index = () => {
  return sayHello(name);
};

ReactDOM.render(<Index />, document.getElementById("index"));
Enter fullscreen mode Exit fullscreen mode

Refresh your browser tab and you will see that the paragraph that is rendered is the first one, that includes the variable we defined. Now, comment the line where we define the name variable and refresh your browser tab. The paragraph that is being renderized now is the second one, with the Hello, nobody message.

Another way of doing conditional rendering is using a ternary operator. It works like this: { condition ? returns this if condition is true : returns this if condition is false }. Let's see the same example that we used above, but using a ternary operator.

import React from "react";
import ReactDOM from "react-dom";

const name = "Felipe";

const Index = () => {
  return (
    <div>
      { name ? <p>Hello { name }!</p> : <p>Hello, nobody</p> }
    </div>
  )
};

ReactDOM.render(<Index />, document.getElementById("index"));
Enter fullscreen mode Exit fullscreen mode

This way is, in my opinion, cleaner and simpler than using an if block, with two pieces of template. You can test doing the same we did previously. Refresh your browser tab, check that the rendered paragraph is the one with the name variable. Then, comment the line where we define it and refresh your browser again.

Also notice that it's also possible to just render something if a condition is true, and not render anything if it's not true. A good example for this would be an error banner. To do this, we can either use the if block without the else part, or use the ternary operator and return null in the last part. Let's see an example with the ternary operator:

import React from "react";
import ReactDOM from "react-dom";

const name = "Felipe";

const Index = () => {
  return (
    <div>
      { name ? <p>Hello { name }!</p> : null }
      <p>How are you?</p>
    </div>
  )
};

ReactDOM.render(<Index />, document.getElementById("index"));
Enter fullscreen mode Exit fullscreen mode

With the code above, both paragraphs will be rendered. However, if you comment the line where the define the name variable, you will see that the paragraph with the Hello will not be shown.

To iterate through a collection of items, instead of using a for loop, where we would need to append the elements to be renderized, we can use map, which already returns the list in the way you need. Let's see how it works:

import React from "react";
import ReactDOM from "react-dom";

const names = ["Felipe", "Jose", "Alfredo"];

const Index = () => {
  return <div>
    {
      names.map((name, count) => {
        return <p key={ count }>Hello, { name }!</p>
      })
    }
  </div>;
};

ReactDOM.render(<Index />, document.getElementById("index"));
Enter fullscreen mode Exit fullscreen mode

In a map, you iterate through a collection and whatever you return will be an element of the new list.

Notice that we defined a value for the key on each element. This value is required when we work with groups of elements, so that React can render everything correctly. If you don't define it, your application will render, but you will get a warning and you may experience some weird behavior when using it.

Element Attributes

Another important thing when developing a React application are the attributes for the JSX elements. The most common one is the class attribute, where we define classes for HTML elements so that they can de stylized using CSS. When working with JSX elements, you should use className instead. Another attribute that is pretty common and is different in JSX is for, widely used on labels when working with forms. In JSX, you have to use htmlFor instead. For a detailed view on all the differences in attributes in JSX elements, you can check this link: https://reactjs.org/docs/dom-elements.html#differences-in-attributes

And this is a good start to understand JSX with React. On our next post, we will talk about components and how to better organize your applications.

Feel free to comment and make suggestions.

Top comments (0)