REACT (https://www.kirupa.com/react/index.htm)
BOOK (https://www.amazon.com/exec/obidos/ASIN/0134546318/kirupacom)
Conditional Rendering in React
by kirupa (https://www.kirupa.com/me/index.htm) | filed under Learning React (https://www.kirupa.com/react/index.htm)
Almost no UI shows the same thing all the time. A menu is open or closed. A user is signed in or signed out. A list is loading, or it failed to load, or it loaded and there is nothing in it. If your app can't show different things at different times, it isn't much of an app.
In React, there is no special syntax for any of this. There is no v-if or *ngIf to learn. Your components are JavaScript functions, and JSX is JavaScript, so you decide what to show using the same if statements, ternaries, and logical operators you already know. What takes a bit of practice is figuring out which one to use when, and a few traps are waiting for you along the way.
In this tutorial, we'll go through each pattern, see when it reads best, and then look at something that surprises almost everyone: what happens to a component's state when you hide it. Onwards!
The Basic Idea
A component is a function, and what it returns is what ends up on the screen. If you want a component to show something different in different situations, you change what the function returns. That's the whole idea behind conditional rendering. Everything else in this tutorial is a different way to express it.
To try the code in this tutorial, create a new Vite project (if you don't have one, follow along with Easily Set Up Your React Dev Environment (https://www.kirupa.com/react/setting_up_react_environment.htm)) and replace the contents of src/App.jsx with whatever example we are looking at. For the examples that use state, we'll use the useState hook. You'll see it fully explained in Dealing with State (https://www.kirupa.com/react/dealing_with_state.htm), so don't worry if some of it looks new. All you need to know for now is that state is a value a component remembers, and changing it makes the component run again with the new value.
Using if and Early Returns
The most direct way to render conditionally is an if statement at the top of your component. Here's a Dashboard that needs a user to be signed in:
function Dashboard({ user }) {
if (!user) {
return
Please sign in to see your dashboard.
;
}
return
Welcome back, {user.name}!
;
}
function App() {
return (
);
}
export default App;
When you run this, you'll see two things: "Please sign in to see your dashboard." for the first Dashboard, and "Welcome back, Batman!" for the second.
The if check at the top is called an early return. If the user is missing, we return right away, and the rest of the function never runs. This has a nice side effect. By the time we reach the main return, we know user exists, so we can use user.name without worrying about it blowing up.
You'll use early returns a lot. They keep the main path of your component flat and easy to read, and the unusual cases get dealt with at the top and out of the way. An if statement can't live inside the JSX itself, though, because JSX curly braces accept expressions and not statements. When you want to decide something in the middle of your JSX, you need a different tool.
The Ternary Operator
The ternary (or conditional) operator is an expression: it takes a condition and gives you one of two values. That means it can go right inside your JSX:
function Greeting({ isLoggedIn }) {
return (
My App
{isLoggedIn ?
Welcome back!
:
Please sign in.
}
);
}
The part before the ? is the condition. If it's true, you get what's between the ? and the :. If it's false, you get what comes after the :. Render and you'll see the welcome message under the heading. Flip it to false and the sign-in message takes its place.
A ternary is the right tool when there are exactly two outcomes and both are short. The moment either side gets long, or you start nesting a ternary inside another ternary, it becomes hard to read. At that point, reach for one of the options we'll see in a bit.
Using && for Show-or-Nothing
Sometimes you don't have an "else" at all. You either show something or you show nothing. A ternary works, but you'd have to write : null every time. The logical AND operator (&&) is a shorter way to say the same thing:
function Inbox({ unread }) {
return (
Inbox
{unread > 0 && {unread} unread}
);
}
Here is how this works. In JavaScript, a && b gives you b if a is truthy. Otherwise, it gives you a. When unread is 5, the condition is true, so we get the . When unread is 0, the condition is false, and React renders nothing for false. Render and you'll see "5 unread" next to the heading. Use unread={0} and you'll see only the heading.
The 0 Gotcha
Now let's make one tiny change. Instead of unread > 0, what if we just use unread as the condition, since a number is truthy when it isn't zero?
function Inbox({ unread }) {
return (
Inbox
{unread && {unread} unread}
);
}
This looks like it should work the same way, and with unread={5} it does. Now render it with unread={0}:
[Image: A page with the heading Inbox followed by a stray number 0 below it] (https://www.kirupa.com/react/images/conditional_zero_gotcha.png)
There's a lonely 0 sitting under our heading! The cause is that 0 && anything gives you 0, since 0 is falsy and && hands back the first falsy value it sees. React doesn't render true, false, null, or undefined, but it does render numbers, and 0 is a number. (An empty string renders as nothing, and NaN will show up as the text "NaN", so numbers are the main culprit.)
The fix is to make sure the left side of the && is a real boolean. Writing unread > 0 && ... does that, and so does Boolean(unread) && .... Anytime the thing on the left is a number, like a length or a count, do this. We touched on this trap briefly in Going from Data to UI (https://www.kirupa.com/react/from_data_to_ui_in_react.htm), and now you know the full story.
Returning null
Sometimes the thing that should disappear is the whole component. For that, your component can return null:
function Banner({ message }) {
if (!message) {
return null;
}
return
{message}
;
}
When a component returns null, React renders nothing for it. It's still a perfectly fine component. It's just invisible for the moment. Our Banner is a good example: whoever uses it can render it all the time and pass in a message when there is something to say. With message="" you'll see nothing, and with message="Hi" you'll see the banner.
This is the same early return we saw earlier, just with an empty result. Whether to let the component decide for itself (return null) or let the parent decide ({message && }) is a style choice. If the logic of "when should I be visible" belongs to the component, put it inside. If it's more about the situation the parent is in, keep it in the parent.
Storing JSX in Variables
Remember that JSX is just a value, and values can be stored in variables. This gives you a pattern that is handy when the condition is complicated, or when each outcome has a fair amount of JSX:
function AccountMenu({ user }) {
let menu;
if (user) {
menu = (
Hi, {user.name}
);
} else {
menu = ;
}
return ;
}
We use a regular if and else to decide what goes into menu, and then we drop menu into the returned JSX. The