How JSX Renders Different Data Types In ReactJS
As a quick experiment, I wanted to see how JXS renders different types of data in ReactJS. And, think about how the rendering algorithm can be leveraged to generate conditional output. Of course, I am referring to "JSX" as the renderer. But really, JSX is just the syntactic sugar over the core ReactJS rendering engine. So, keep that in mind as you read this - I am using terms a bit loosely.
Run this demo in my JavaScript Demos project on GitHub.
To test the rendering of different data types, in JSX, I've put together a simple ReactJS app that passes different data values off to the "{ value }" syntax:
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title>
How JSX Renders Different Data Types In ReactJS
</title>
</head>
<body>
<h1>
How JSX Renders Different Data Types In ReactJS
</h1>
<div id="content">
<!-- This content will be replaced with the React rendering. -->
</div>
<!-- Load scripts. -->
<script src="../../vendor/reactjs/react-0.13.3.min.js"></script>
<script src="../../vendor/reactjs/JSXTransformer-0.13.3.js"></script>
<script type="text/jsx">
// I manage the Demo widget.
var Demo = React.createClass({
// I render the component based on the current state.
render: function() {
var array = [ 1, 2, 3 ];
var object = {
name: "Winnie",
status: "Honey lover."
};
return(
<ul>
<li>
True: { true }
</li>
<li>
False: { false }
</li>
<li>
Number: { 4.5 }
</li>
<li>
Number(0): { 0 } { /* Testing for numeric Falsey values. */ }
</li>
<li>
String: { "Hello world!" }
</li>
<li>
Null: { null }
</li>
<li>
Array: { array }
</li>
<li>
Object: { object }
</li>
<li>
NaN: { ( "foo" * 3 ) }
</li>
<li>
Infinity: { ( 3 / 0 ) }
</li>
<li>
Undefined: { document.foo }
</li>
</ul>
);
}
});
// --------------------------------------------------------------------------- //
// --------------------------------------------------------------------------- //
// Render the root Demo and mount it inside the given element.
React.render( <Demo />, document.getElementById( "content" ) );
</script>
</body>
</html>
I'm trying to see not only how JSX renders different data types; but, also, how it renders different data values that can all be considered "Falsey" values. When we run this code, we get the following browser output:
There are a number of interesting behaviors going on here:
- True, False, Null, and Undefined (sorry, not in the demo) values are not rendered.
- Each value of an Array is rendered individually.
- Each key-value pair of an object is rendered individually.
Off-hand, I can't think of a use-case of Object rendering (yet); but, Array rendering is quite core to the way ReactJS works. Typically, we see Array rendering when a collection of data points are mapped (using ES5's .map() method) onto a collection of React Elements. But, we can also use Array rendering to render inline collections of mixed data, as seen in the documentation:
{ [ variableA, <span> — </span>, variableB ] }
But, the feature that I really want to look at is the non-rendering of False. Since JSX, and ReactJS, don't render False values, it means that we can leverage the logical AND operator to conditionally output string values.
To demonstrate this, I'm going to render a list of friends where each friend may be a BFF (Best Friends Forever, yo!). If a particular friend is a BFF, I want to render some additional output:
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title>
Leverage Truthy JSX Rendering For Conditional Output In ReactJS
</title>
</head>
<body>
<h1>
Leverage Truthy JSX Rendering For Conditional Output In ReactJS
</h1>
<div id="content">
<!-- This content will be replaced with the React rendering. -->
</div>
<!-- Load scripts. -->
<script src="../../vendor/reactjs/react-0.13.3.min.js"></script>
<script src="../../vendor/reactjs/JSXTransformer-0.13.3.js"></script>
<script type="text/jsx">
// I manage the Demo widget.
var Demo = React.createClass({
// I render the component based on the current state.
render: function() {
// With this collection of friends, there is an "isBFF" flag that we want
// to use to conditionally render some additional output.
var friends = [
{
id: 1,
name: "Joanna",
isBFF: false
},
{
id: 2,
name: "Kim",
isBFF: true
},
{
id: 3,
name: "Sarah",
isBFF: false
}
];
// Map the friends onto LI elements.
var listItems = friends.map(
function iterator( friend, i ) {
return(
<li key={ friend.id }>
{ friend.name }
{
// Notice that we can leverage Truthy / Falsey
// rendering, in JSX, to conditionally render a string
// based on a logical outcome. Since JSX will not
// render [false], then any condition that results in
// [false] will not be rendered. However, in JavaScript,
// the [&&] and [||] operators will return the last
// evaluated value in the condition, which in our case,
// is the string that we want to render.
// --
// CAUTION: If [isBFF] is a number, like "0", then it
// will be rendered since JSX will render Falsey numbers.
}
{ friend.isBFF && " \u2014 Oh man, she's the best!" }
</li>
);
}
);
return(
<ul>
{ listItems }
</ul>
);
}
});
// --------------------------------------------------------------------------- //
// --------------------------------------------------------------------------- //
// Render the root Demo and mount it inside the given element.
React.render( <Demo />, document.getElementById( "content" ) );
</script>
</body>
</html>
Run this demo in my JavaScript Demos project on GitHub.
Notice that "friend.isBFF" is being used to drive the conditional output. And, when we run the above code, we get the following output:
- Joanna
- Kim -- Oh man, she's the best!
- Sarah
If you look in the above code, you'll notice that I have to encode the mdash as the unicode character \u2014. This is required because HTML, within a string, will be escaped. To get around this somewhat awkward and unreadable notation, we can actually leverage the same behavior to conditionally output full-fledged React Elements, not just string values. This time, rather than AND'ing the isBFF flag with a string, we're going to AND it with a React Element:
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title>
Leverage Truthy JSX Rendering For Conditional Output In ReactJS
</title>
</head>
<body>
<h1>
Leverage Truthy JSX Rendering For Conditional Output In ReactJS
</h1>
<div id="content">
<!-- This content will be replaced with the React rendering. -->
</div>
<!-- Load scripts. -->
<script src="../../vendor/reactjs/react-0.13.3.min.js"></script>
<script src="../../vendor/reactjs/JSXTransformer-0.13.3.js"></script>
<script type="text/jsx">
// I manage the Demo widget.
var Demo = React.createClass({
// I render the component based on the current state.
render: function() {
// With this collection of friends, there is an "isBFF" flag that we want
// to use to conditionally render some additional output.
var friends = [
{
id: 1,
name: "Joanna",
isBFF: false
},
{
id: 2,
name: "Kim",
isBFF: true
},
{
id: 3,
name: "Sarah",
isBFF: false
}
];
// Map the friends onto LI elements.
var listItems = friends.map(
function iterator( friend, i ) {
{
// Rather than using the logical AND operator to output a
// simple string value, we're going to use it to conditionally
// output a React Element.
}
var bffElement = ( <span> — Oh man, shes the best!</span> );
return(
<li key={ friend.id }>
{ friend.name }
{ friend.isBFF && bffElement }
</li>
);
}
);
return(
<ul>
{ listItems }
</ul>
);
}
});
// --------------------------------------------------------------------------- //
// --------------------------------------------------------------------------- //
// Render the root Demo and mount it inside the given element.
React.render( <Demo />, document.getElementById( "content" ) );
</script>
</body>
</html>
Run this demo in my JavaScript Demos project on GitHub.
Running this produces the output as above. This, to me, is very exciting because I think this entire concept of AND-based conditional output can be used to greatly simplify some of the rendering techniques. Rather than conditionally defining a value, you can always define it; then, just render it under certain conditions.
Sometimes, when you look at demos, it's easy to lose sight of what is going on. By stepping back and looking at how JSX and ReactJS render different data types, I think it can give us more insight into the process and, therefore, more opportunity to control how rendering takes place in our ReactJS components.
Want to use code from this post? Check out the license.
Reader Comments
Really cool and helpful. Without understanding the underlying behavior, ` { bool && element }` isn't very intuitive. I could see it being quite confusing for someone looking at the code for their first time. Without your explanation, I would have expected a true/false output. Thanks @Ben.
@Josh,
Yeah, I think you're right. This is definitely not very intuitive. But, there is something nice about it. I think once you get used to the concept, it can make the code easier to reason about.
@All,
As a quasi follow-up to this, I wanted to take a quick look at how white space gets rendered in JSX and ReactJS:
www.bennadel.com/blog/2880-a-quick-look-at-rendering-white-space-using-jsx-in-reactjs.htm
It kept tripping me up in the beginning. But, once you understand the rules, it's easy to work around.
@All,
Just came across this in the "Tips" documentation for React:
http://facebook.github.io/react/tips/false-in-jsx.html
It looks like this is exactly why they don't render False/Null values -- to be able to enable the "&&" approach to rendering. So, at least they are intentful about it.