In this article by Michele Bertoli, the author of the book React Design Patterns and Best Practices, we will learn to use JSX without any problems or unexpected behaviors, it is important to understand how it works under the hood and the reasons why it is a useful tool to build UIs.
Our goal is to write clean and maintainable JSX code and to achieve that we have to know where it comes from, how it gets translated to JavaScript and which features it provides.
In the first section, we will do a little step back but please bear with me because it is crucial to master the basics to apply the best practices.
In this article, we will see:
(For more resources related to this topic, see here.)
Let's see how we can declare our elements inside our components.
React gives us two ways to define our elements: the first one is by using JavaScript functions and the second one is by using JSX, an optional XML-like syntax.
In the beginning, JSX is one of the main reasons why people fails to approach to React because looking at the examples on the homepage and seeing JavaScript mixed with HTML for the first time does not seem right to most of us.
As soon as we get used to it, we realize that it is very convenient exactly because it is similar to HTML and it looks very familiar to anyone who already created User Interfaces on the web.
The opening and closing tags, make it easier to represent nested trees of elements, something that would have been unreadable and hard to maintain using plain JavaScript.
In order to use JSX (and es2015) in our code, we have to install Babel.
First of all, it is important to understand clearly the problems it can solve for us and why we need to add a step in our process. The reason is that we want to use features of the language that have not been implemented yet in the browser, our target environment. Those advanced features make our code more clean for the developers but the browser cannot understand and execute it.
So the solution is to write our scripts in JSX and es2015 and when we are ready to ship, we compile the sources into es5, the standard specification that is implemented in the major browsers today.
Babel is a popular JavaScript compiler widely adopted within the React community:
It can compile es2015 code into es5 JavaScript as well as compile JSX into JavaScript functions. The process is called transpilation, because it compiles the source into a new source rather than into an executable.
Using it is pretty straightforward, we just install it:
npm install --global babel-cli
If you do not like to install it globally (developers usually tend to avoid it), you can install Babel locally to a project and run it through a npm script but for the purpose of this article a global instance is fine.
When the installation is completed we can run the following command to compile our JavaScript files:
babel source.js -o output.js
One of the reasons why Babel is so powerful is because it is highly configurable. Babel is just a tool to transpile a source file into an output file but to apply some transformations we need to configure it.
Luckily, there are some very useful presets of configurations which we can easily install and use:
npm install --global babel-preset-es2015 babel-preset-react
Once the installation is done, we create a configuration file called .babelrc and put the following lines into it to tell Babel to use those presets:
{
"presets": [
"es2015",
"React"
]
}
From this point on we can write es2015 and JSX in our source files and execute the output files in the browser.
Now that our environment has been set up to support JSX, we can dive into the most basic example: generating a div element.
This is how you would create a div with React'screateElementfunction:
React.createElement('div')
React has some shortcut methods for DOM elements and the following line is equivalent to the one above:
React.DOM.div()
This is the JSX for creating a div element:
<div />
It looks identical to the way we always used to create the markup of our HTML pages.
The big difference is that we are writing the markup inside a .js file but it is important to notice that JSX is only a syntactic sugar and it gets transpiled into the JavaScript before being executed in the browser.
In fact, our <div /> is translated into React.createElement('div') when we run Babel and that is something we should always keep in mind when we write our templates.
With JSX we can obviously create both HTML elements and React components, the only difference is if they start with a capital letter or not.
So for example to render an HTML button we use <button />, while to render our Button components we use <Button />.
The first button gets transpiled into:
React.createElement('button')
While the second one into:
React.createElement(Button)
The difference here is that in the first call we are passing the type of the DOM element as a string while in the second one we are passing the component itself, which means that it should exist in the scope to work.
As you may have noticed, JSX supports self-closing tags which are pretty good to keep the code terse and they do not require us to repeat unnecessary tags.
JSX is very convenient when your DOM elements or React components have props, in fact following XML is pretty easy to set attributes on elements:
<imgsrc="https://facebook.github.io/react/img/logo.svg" alt="React.js" />
The equivalent in JavaScript would be:
React.createElement("img", {
src: "https://facebook.github.io/react/img/logo.svg",
alt: "React.js"
});
Which is way less readable and even with only a couple of attributes it starts getting hard to be read without a bit of reasoning.
JSX allows you to define children to describe the tree of elements and compose complex UIs.
A basic example could be a link with a text inside it:
<a href="https://facebook.github.io/react/">Click me!</a>
Which would be transpiled into:
React.createElement(
"a",
{ href: "https://facebook.github.io/react/" },
"Click me!"
);
Our link can be enclosed inside a div for some layout requirements and the JSX snippet to achieve that is the following:
<div>
<a href="https://facebook.github.io/react/">Click me!</a>
</div>
With the JSX equivalent being:
React.createElement(
"div",
null,
React.createElement(
"a",
{ href: "https://facebook.github.io/react/" },
"Click me!"
)
);
It becomes now clear how the XML-like syntax of JSX makes everything more readable and maintainable but it is always important to know what is the JavaScript parallel of our JSX to take control over the creation of elements.
The good part is that we are not limited to have elements as children of elements but we can use JavaScript expressions like functions or variables.
For doing that we just have to put the expression inside curly braces:
<div>
Hello, {variable}.
I'm a {function()}.
</div>
The same applies to non-string attributes:
<a href={this.makeHref()}>Click me!</a>
So far we have seen how the JSX is similar to HTML, let's now see the little differences between them and the reasons why they exist.
We always have to keep in mind that JSX is not a standard language and it gets transpiled into JavaScript and because of that, some attributes cannot be used.
For example instead of class we have to use className and instead of for we have to use htmlFor:
<label className="awesome-label"htmlFor="name" />
The reason is that class and for are reserved word in JavaScript.
A pretty significant difference is the way the style attribute works.The style attribute does not accept a CSS string as the HTML parallel does, but it expects a JS Object where the style names are camelCased.
<div style={{ backgroundColor: 'red' }} />
One important difference with HTML worth mentioning is that since JSX elements get translated into JavaScript functions and you cannot return two functions in JavaScript, whenever you have multiple elements at the same level you are forced to wrap them into a parent.
Let's see a simple example:
<div />
<div />
Gives us the following error:
Adjacent JSX elements must be wrapped in an enclosing tag
While this:
<div>
<div />
<div />
</div>
It is pretty annoying having to add unnecessary divtags just for making JSX work but the React developers are trying to find a solution:
https://github.com/reactjs/core-notes/blob/master/2016-07/july-07.md
There's one thing that could be a little bit tricky at the beginning and again it regards the fact that we should always have in mind that JSX is not HTML, even if it has an XML-like syntax.
JSX, in fact, handles the spaces between text and elements differently from HTML in a way that's counter-intuitive.
Consider the following snippet:
<div>
<span>foo</span>
bar
<span>baz</span>
</div>
In the browser, which interprets HTML, this code would give you foo bar baz, which is exactly what we expect it to be.
In JSX instead, the same code would be rendered as foobarbaz and that is because the three nested lines get transpiled as individual children of the div element, without taking in account the spaces.
A common solution is to put a space explicitly between the elements:
<div>
<span>foo</span>
{''}
bar
{''}
<span>baz</span>
</div>
As you may have noticed, we are using an empty string wrapped inside a JavaScript expression to force the compiler to apply the space between the elements.
A couple of more things worth mentioning before starting for real regard the way you define Boolean attributes in JSX. If you set an attribute without a value, JSX assumes that its value is true, following the same behavior of the HTML disabled attribute, for example.
That means that if we want to set an attribute to false we have to declare it explicitly to false:
<button disabled />
React.createElement("button", { disabled: true });
And:
<button disabled={false} />
React.createElement("button", { disabled: false });
This can be confusing in the beginning because we may think that omitting an attribute would mean false but it is not like that: with React we should always be explicit to avoid confusion.
An important feature is the spread attributes operator, which comes from the Rest/Spread Properties for ECMAScript proposal and it is very convenient whenever we want to pass all the attributes of a JavaScript object to an element.
A common practice that leads to fewer bugs is not to pass entire JavaScript objects down to children by reference but using their primitive values which can be easily validated making components more robust and error proof.
Let's see how it works:
const foo = { bar: 'baz' }
return <div {...foo} />
That gets transpiled into this:
var foo = { bar: 'baz' };
return React.createElement('div', foo);
JavaScript templating
Last but not least, we started from the point that one of the advantages of moving the templates inside our components instead of using an external template library is that we can use the full power of JavaScript, so let's start looking at what it means.
The spread attributes is obviously an example of that and another common one is that JavaScript expressions can be used as attributes values by wrapping them into curly braces:
<button disabled={errors.length} />
Now that we know how JSX works and we master it, we are ready to see how to use it in the right way following some useful conventions and techniques.
Let's start with a very simple one: as we said, on the main reasons why we should prefer JSX over React'screateClass is because of its XML-like syntax and the way balanced opening/closing tags are perfect to represent a tree of nodes.
Therefore, we should try to use it in the right way and get the most out of it.
One example is that, whenever we have nested elements, we should always go multi-line:
<div>
<Header />
<div>
<Main content={...} />
</div>
</div>
Instead of:
<div><Header /><div><Main content={...} /></div></div>
Unless the children are not elements, such as text or variables. In that case it can make sense to remain on the same line and avoid adding noise to the markup, like:
<div>
<Alert>{message}</Alert>
<Button>Close</Button>
</div>
Always remember to wrap your elements inside parenthesis when you write them in multiple lines. In fact, JSX always gets replaced by functions and functions written in a new line can give you an unexpected result. Suppose for example that you are returning JSX from your render method, which is how you create UIs in React.
The following example works fine because the div is in the same line of the return:
return <div />
While this is not right:
return
<div />
Because you would have:
return;
React.createElement("div", null);
That is why you have to wrap the statement into parenthesis:
return (
<div />
)
Multi-properties
A common problem in writing JSX comes when an element has multiples attributes. One solution would be to write all the attributes on the same line but this would lead to very long lines which we do not want in our code (see in the next section how to enforce coding style guides).
A common solution is to write each attribute on a new line with one level of indentation and then putting the closing bracket aligned with the opening tag:
<button
foo="bar"
veryLongPropertyName="baz"
onSomething={this.handleSomething}
/>
Conditionals
Things get more interesting when we start working with conditionals, for example if we want to render some components only when some conditions are matched. The fact that we can use JavaScript is obviously a plus but there are many different ways to express conditions in JSX and it is important to understand the benefits and the problems of each one of those to write code that is readable and maintainable at the same time.
Suppose we want to show a logout button only if the user is currently logged in into our application.
A simple snippet to start with is the following:
let button
if (isLoggedIn) {
button = <LogoutButton />
}
return <div>{button}</div>
It works but it is not very readable, especially if there are multiple components and multiple conditions.
What we can do in JSX is using an inline condition:
<div>
{isLoggedIn&&<LoginButton />}
</div>
This works because if the condition is false, nothing gets rendered but if the condition is true the createElement function of the Loginbutton gets called and the element is returned to compose the resulting tree.
If the condition has an alternative, the classic if…else statement, and we want for example to show a logout button if the user is logged in and a login button otherwise, we can either use JavaScript's if…else:
let button
if (isLoggedIn) {
button = <LogoutButton />
} else {
button = <LoginButton />
}
return <div>{button}</div>
Alternatively, better, using a ternary condition, which makes our code more compact:
<div>
{isLoggedIn ? <LogoutButton /> : <LoginButton />}
</div>
You can find the ternary condition used in popular repositories like the Redux real world example (https://github.com/reactjs/redux/blob/master/examples/real-world/src/components/List.js) where the ternary is used to show a loading label if the component is fetching the data or "load more" inside a button according to the value of the isFetching variable:
<button [...]>
{isFetching ? 'Loading...' : 'Load More'}
</button>
Let's now see what is the best solution when things get more complicated and, for example, we have to check more than one variable to determine if render a component or not:
<div>
{dataIsReady&& (isAdmin || userHasPermissions) &&<SecretData />}
</div>
In this case is clear that using the inline condition is a good solution but the readability is strongly impacted so what we can do instead is creating a helper function inside our component and use it in JSX to verify the condition:
canShowSecretData() {
const { dataIsReady, isAdmin, userHasPermissions } = this.props
return dataIsReady&& (isAdmin || userHasPermissions)
}
<div>
{this.canShowSecretData() &&<SecretData />}
</div>
As you can see, this change makes the code more readable and the condition more explicit. Looking into this code in six month time you will still find it clear just by reading the name of the function.
If we do not like using functions you can use object's getters which make the code more elegant.
For example, instead of declaring a function we define a getter:
get canShowSecretData() {
const { dataIsReady, isAdmin, userHasPermissions } = this.props
return dataIsReady&& (isAdmin || userHasPermissions)
}
<div>
{this.canShowSecretData&&<SecretData />}
</div>
The same applies to computed properties: suppose you have two single properties for currency and value. Instead of creating the price string inside you render method you can create a class function for that:
getPrice() {
return `${this.props.currency}${this.props.value}`
}
<div>{this.getPrice()}</div>
Which is better because it is isolated and you can easily test it in case it contains logic.
Alternatively going a step further and, as we have just seen, use getters:
get price() {
return `${this.props.currency}${this.props.value}`
}
<div>{this.price}</div>
Going back to conditional statements, there are other solutions that require using external dependencies. A good practice is to avoid external dependencies as much as we can to keep our bundle smaller but it may be worth it in this particular case because improving the readability of our templates is a big win.
The first solution is renderIf which we can install with:
npm install --save render-if
And easily use in our projects like this:
const { dataIsReady, isAdmin, userHasPermissions } = this.props
constcanShowSecretData = renderIf(dataIsReady&& (isAdmin || userHasPermissions))
<div>
{canShowSecretData(<SecretData />)}
</div>
We wrap our conditions inside the renderIf function.
The utility function that gets returned can be used as a function that receives the JSX markup to be shown when the condition is true.
One goal that we should always keep in mind is never to add too much logic inside our components. Some of them obviously will require a bit of it but we should try to keep them as simple and dumb as possible in a way that we can spot and fix error easily.
At least, we should try to keep the renderIf method as clean as possible and for doing that we could use another utility library called React Only If which let us write our components as if the condition is always true by setting the conditional function using a higher-order component.
To use the library we just need to install it:
npm install --save react-only-if
Once it is installed, we can use it in our apps in the following way:
constSecretDataOnlyIf = onlyIf(
SecretData,
({ dataIsReady, isAdmin, userHasPermissions }) => {
return dataIsReady&& (isAdmin || userHasPermissions)
}
)
<div>
<SecretDataOnlyIf
dataIsReady={...}
isAdmin={...}
userHasPermissions={...}
/>
</div>
As you can see here there is no logic at all inside the component itself.
We pass the condition as the second parameter of the onlyIf function when the condition is matched, the component gets rendered.
The function that is used to validate the condition receives the props, the state, and the context of the component.
In this way we avoid polluting our component with conditionals so that it is easier to understand and reason about.
A very common operation in UI development is displaying lists of items. When it comes to showing lists we realize that using JavaScript as a template language is a very good idea.
If we write a function that returns an array inside our JSX template, each element of the array gets compiled into an element.
As we have seen before we can use any JavaScript expressions inside curly braces and the more obvious way to generate an array of elements, given an array of objects is using map.
Let's dive into a real-world example, suppose you have a list of users, each one with a name property attached to it.
To create an unordered list to show the users you can do:
<ul>
{users.map(user =><li>{user.name}</li>)}
</ul>
This snippet is in incredibly simple and incredibly powerful at the same time, where the power of the HTML and the JavaScript converge.
Conditional and loops are very common operations in UI templates and you may feel wrong using the JavaScript ternary or the map function to do that. JSX has been built in a way that it only abstract the creation of the elements leaving the logic parts to real JavaScript which is great but sometimes the code could become less clear.
In general, we aim to remove all the logic from our components and especially from our render method but sometimes we have to show and hide elements according to the state of the application and very often we have to loop through collections and arrays.
If you feel that using JSX for that kind of operations would make your code more readable there is a Babel plugin for that: jsx-control-statements.
It follows the same philosophy of JSX and it does not add any real functionality to the language, it is just a syntactic sugar that gets compiled into JavaScript.
Let's see how it works.
First of all, we have to install it:
npm install --save jsx-control-statements
Once it is installed we have to add it to the list of our babel plugins in our .babelrc file:
"plugins": ["jsx-control-statements"]
From now on we can use the syntax provided by the plugin and Babel will transpile it together with the common JSX syntax.
A conditional statement written using the plugin looks like the following snippet:
<If condition={this.canShowSecretData}>
<SecretData />
</If>
Which get transpiled into a ternary expression:
{canShowSecretData ? <SecretData /> : null}
The If component is great but if for some reasons you have nested conditions in your render method it can easily become messy and hard to follow. Here is where the Choose component comes to help:
<Choose>
<When condition={...}>
<span>if</span>
</When>
<When condition={...}>
<span>else if</span>
</When>
<Otherwise>
<span>else</span>
</Otherwise>
</Choose>
Please notice that the code above gets transpiled into multiple ternaries.
Last but not least there is a "component" (always remember that we are not talking about real components but just a syntactic sugar) to manage the loops which is very convenient as well.
<ul>
<For each="user" of={this.props.users}>
<li>{user.name}</li>
</For>
</ul>
The code above gets transpiled into a map function, no magic in there.
If you are used to using linters, you might wonder how the linter is not complaining about that code. In fact, the variable item doesn't exist before the transpilation nor it is wrapped into a function. To avoid those linting errors there's another plugin to install: eslint-plugin-jsx-control-statements.
If you did not understand the previous sentence don't worry: in the next section we will talk about linting.
It is worth stressing that we always want to keep our components very small and our render methods very clean and simple.
However, that is not an easy goal, especially when you are creating an application iteratively and in the first iteration you are not sure exactly how to split the components into smaller ones.
So, what should we be doing when the render method becomes big to keep it maintainable? One solution is splitting it into smaller functions in a way that let us keeping all the logic in the same component.
Let's see an example:
renderUserMenu() {
// JSX for user menu
}
renderAdminMenu() {
// JSX for admin menu
}
render() {
return (
<div>
<h1>Welcome back!</h1>
{this.userExists&&this.renderUserMenu()}
{this.userIsAdmin&&this.renderAdminMenu()}
</div>
)
}
This is not always considered a best practice because it seems more obvious to split the component into smaller ones but sometimes it helps just to keep the render method cleaner. For example in the Redux Real World examples a sub-render method is used to render the load more button.
Now that we are JSX power user it is time to move on and see how to follow a style guide within our code to make it consistent.
In this article we deeply understood how JSX works and how to use it in the right way in our components. We started from the basics of the syntax to create a solid knowledge that will let us mastering JSX and its features.
Further resources on this subject: