Conditional rendering in JSX is one of the best ways to “level up” your components. When developing React components, there are many times when you need a bit of markup to be more dynamic – that is to say, it may change depending on different factors.
In this guide, we’ll explore a powerful feature of React – the ability to embed JavaScript logic inside of JSX code.
In the previous article in this series, we learned how to add event listeners to React components. Check out that guide if you haven’t already!
Prerequisite Knowledge
- JavaScript expressions, particularly Boolean expressions
- JavaScript ternary operator (
? :
) - JavaScript array methods, particularly the
map
method - Basic rules of JSX
Contents
Rendering a List of Items
Let’s use a very generic example: imagine you’re making a Todo List application. In this application, you probably have an array called something like todoItems
that contains every item in the todo list.
Then you have two React components: <TodoList />
and <TodoItem />
. TodoList
renders a list (<ul> </ul>
) of TodoItem
s.
The result you’re looking for is something like this:
<TodoList>
<TodoItem item={todoItems[0]} />
<TodoItem item={todoItems[1]} />
<TodoItem item={todoItems[2]} />
// And so on for the rest of the array...
</TodoList>
Obviously, this is not a good solution. The size of the array will be constantly changing as todo items are added and deleted. What we need is a way to dynamically render the correct number of TodoItem
components based on the size of the array.
This is what you’ll learn how to do.
For simplicity, we’ll be sticking to the same Todo List example, adding more complexity as we progress.
JSX Braces Syntax
You should already know this bit if you have read up on the basic rules of JSX, but in case you haven’t, let’s do a quick review.
To embed JavaScript logic or expressions into JSX code, we use curly braces { }
. This allows us to, for example, display the contents of a variable, or pass a variable as a prop to a component.
// Displaying a variable
const name = 'theLoneCoder';
<h1> My name is {name}</h1>
// Passing data to a component
const data = 52.785; // Just a random number...
<DisplayData data={data} />
Curly braces can also be used to do a lot more: we can change the way our components are displayed, or set up conditions for the rendering. Now, let’s look at the three most common patterns for using JS logic in JSX markup.
Common JSX Logic Patterns
<array>.map(<element> => <JSX expression>)
Going back to our TodoList example, let’s look at the best way to render the todoItems
array. Below is an implementation of the <TodoList />
component.
import TodoItem from './TodoItem'; // Or wherever the component is located
const todoItems = [
{
title: 'Do the dishes',
id: 1
},
{
title: 'Finish the React project',
id: 2
}
];
const TodoList = () => {
return (
<div id='todolist'>
{
todoItems.map(item => <TodoItem item={item} />)
}
</div>
)
};
For each element in the todoItems
array, we are returning a <TodoItem />
component, passing the element as a prop. The resulting markup is essentially the same as our first, inefficient example, but we are accomplishing it with a single line of code.
<boolean expression> && <JSX expression>
It is very common to only render a certain component when a certain condition is true. A common pattern is to have an isActive
boolean variable, and only render a component when it is true.
As another example, you may have an isLoggedIn
variable, and if it’s true, you will render a <Profile />
component.
Both examples are illustrated below:
// NOTE: the Boolean variables would normally be
// React state variables. I am using normal JS variables here
// for those learners who have not yet learned state.
// EXAMPLE 1
import ChildComponent from 'some-directory';
const ParentComponent = () => {
let isChildActive = true;
return (
<div>
{isChildActive && <ChildComponent />}
</div>
);
};
// EXAMPLE 2
import Profile from 'some-directory';
import Feed from 'some-directory'; // Just a generic component...
const Home = () => {
let isLoggedIn = false;
return (
<div>
<Feed />
{isLoggedIn && <Profile />}
</div>
);
};
In our TodoList example, we could use this pattern to ensure that every displayed TodoItem
matches a certain filter. Let’s add on to our little TodoList app, adding a filter feature.
You’ll notice that I’m adding a new property to each todo item called completed
. This will be used in our Boolean expression.
import TodoItem from './TodoItem'; // Or wherever the component is located
const todoItems = [
{
title: 'Do the dishes',
id: 1,
completed: true
},
{
title: 'Finish the React project',
id: 2,
completed: false
}
];
const TodoList = () => {
return (
<div id='todolist'>
{
todoItems.filter(item => item.completed).map(item => {
return <TodoItem item={item} />;
})
}
</div>
)
};
In the above example, we are now filtering the todoItems
array based on the value of each items completed
property. That way, only the completed todo items make it to the map
function call.
<boolean expression> ? <JSX expression> : <JSX expression 2>
One of the most useful patterns of JSX logic uses the JaVAScript ternary/logical operator ? :
. This allows you to return two separate expressions for any given Boolean expression: one will return if the Boolean is true, and the other if it is false.
Going back to our TodoList example – what if we want to turn off the filter? Most of the time, it’s actually more important to view our uncompleted todo list items!
The ternary operator is perfect for this. Let’s add another variable to the app called showCompletedOnly
. We will only filter out the completed items if this variable is true
.
import TodoItem from './TodoItem'; // Or wherever the component is located
const todoItems = [
{
title: 'Do the dishes',
id: 1,
completed: true
},
{
title: 'Finish the React project',
id: 2,
completed: false
}
];
let showCompletedOnly = true;
const TodoList = () => {
return (
<div id='todolist'>
{
todoItems.filter(item => {
return showCompletedOnly ? item.completed : true;
}).map(item => {
return <TodoItem item={item} />;
})
}
</div>
)
};
If the showCompletedOnly
is on (set to true
) then we filter out the completed items. If the filter is off, then we return true
from the filter callback, which simply gives us all of the unfiltered todo items.
Let’s look at one more example. Back in our example with the isLoggedIn
Boolean variable, if the variable was false then we simply didn’t render the <Profile />
component. But what if, instead, we wanted to render a “SIGN IN” link? This is a perfect use of the ternary operator.
import Profile from 'some-directory';
import Feed from 'some-directory'; // Just a generic component...
const Home = () => {
let isLoggedIn = false;
return (
<div>
<Feed />
{isLoggedIn ? (
<Profile />
) : (
<a href='/login'>SIGN IN</a>
)}
</div>
);
};
Great! Now you can write more complex JSX code, that allows you to add more smarts to your components. In the next article, we’re going to discover something called state.