Real pages show different things at different times. A person who is signed in sees their name, and a visitor sees a Sign in button. A list that is empty shows a friendly message. A page that is loading shows a spinner. Showing different content depending on a condition is called conditional rendering. In React there is no special syntax for it. You use plain JavaScript, which makes it easy to learn.
Way 1: an if statement before the return
A component is a function, so you can use if before you return. This is the clearest way when the screens are very different.
function Greeting({ isLoggedIn }) {
if (isLoggedIn) {
return <h2>Welcome back!</h2>;
}
return <h2>Please sign in.</h2>;
}
When the first return runs, the function stops, so the second line is only reached when isLoggedIn is false. This idea is called an early return, and it keeps code flat and easy to read.
Way 2: the ternary operator
Inside JSX you cannot write an if statement, because curly braces accept only expressions. The ternary operator is an expression with three parts: condition ? valueIfTrue : valueIfFalse.
function Status({ isOnline }) {
return (
<p>
The user is {isOnline ? 'online' : 'offline'}.
</p>
);
}
function Badge({ isOnline }) {
return (
<span className={isOnline ? 'badge green' : 'badge grey'}>
{isOnline ? <b>Online</b> : <i>Offline</i>}
</span>
);
}
You can use a ternary for text, for attribute values, and for whole pieces of JSX. If you find yourself nesting one ternary inside another, stop: it becomes very hard to read. Use if or a small component instead.
Way 3: the && operator
When you want to show something or nothing, use &&. In JavaScript, a && b gives b if a is true, and gives a if it is false. React shows nothing for false, so this works as a simple “show this only if” rule.
function Inbox({ unread }) {
return (
<div>
<h2>Inbox</h2>
{unread > 0 && <p>You have {unread} new messages.</p>}
</div>
);
}
Way 4: save JSX in a variable
For bigger choices, you can pick the content first and then show it:
function Panel({ role }) {
let content;
if (role === 'admin') {
content = <AdminTools />;
} else if (role === 'editor') {
content = <EditorTools />;
} else {
content = <p>You can only read.</p>;
}
return <section>{content}</section>;
}
Another handy way is an object that maps a value to a component:
const screens = {
home: <Home />,
about: <About />,
contact: <Contact />,
};
function Page({ name }) {
return screens[name] || <NotFound />;
}
The three screens every data page needs
When a page loads data, it is always in one of three situations: it is still loading, it failed, or it has data. If you forget one of them, people see a blank page or a crash. A good pattern is to handle the unusual cases first with early returns:
function JobList({ jobs, loading, error }) {
if (loading) return <p>Loading jobs...</p>;
if (error) return <p role="alert">Sorry, we could not load the jobs. Please try again.</p>;
if (jobs.length === 0) return <p>No jobs yet. Add your first one!</p>;
return (
<ul>
{jobs.map((job) => (
<li key={job.id}>{job.title}</li>
))}
</ul>
);
}
Because each unusual case returns early, the last part of the function only has to think about the happy case. This is much easier to read than a deep chain of if and else. Also notice the empty state: an empty list is not an error, and a helpful message with a next step is kinder than a blank space.
Showing nothing
A component can return null to show nothing. This is useful when a component decides not to appear:
function Banner({ message }) {
if (!message) return null;
return <div className="banner">{message}</div>;
}
Hiding with CSS or removing from the page?
With conditional rendering, a hidden element is removed from the page, and any state inside it is lost. When it comes back, it starts fresh. If you want to keep the state, or want a fade animation, you can hide the element with CSS instead (for example the hidden attribute or display: none). Choose based on what you need:
- Remove it (conditional rendering): saves work and memory, resets the state.
- Hide it (CSS): keeps the state, allows animation, but the component still exists.
Choosing between the ways
- Two very different screens: early return with
if. - Choose between two small things inside JSX: ternary.
- Show something or nothing: && with a true/false left side.
- Many choices: a variable with
if/else, aswitch, or an object map.
Common mistakes
{count && <List />}whencountcan be0. It shows0. Usecount > 0 &&.- Nested ternaries that nobody can read. Use
ifor split into components. - Trying to write
{if (x) {...}}in JSX. Statements are not allowed inside braces. - Forgetting the empty and error cases for data pages.
- Reading
user.namewhenusercan benull. Checkuser &&first, or useuser?.name.
The last item uses optional chaining, written ?.. It stops safely and gives undefined if the value before it is null or undefined, instead of crashing. It is very useful when data has not arrived yet.
Putting it together: a small account menu
Here is a menu that uses several of the ideas from this lesson at once: an early return, a ternary and &&.
function AccountMenu({ user, loading, unread }) {
if (loading) return <p>Checking your account...</p>;
if (!user) return <a href="/login">Sign in</a>;
return (
<div>
<p>Hello, {user.name}!</p>
{unread > 0 && <p role="status">You have {unread} new messages.</p>}
{user.isAdmin ? <a href="/admin">Admin area</a> : <a href="/account">My account</a>}
</div>
);
}
Each line has one clear job. The first two lines handle the unusual cases and finish early. After that, the code only thinks about a signed-in user. This habit, handling the odd cases first, keeps components flat and easy to read, even when they grow.
Questions beginners often ask
Which way should I choose? Pick the one that makes the code easiest to read. A short ternary for text, && for show-or-nothing, and early returns for whole screens. If you cannot read your own condition in one go, split it into a variable with a clear name, such as const canEdit = user && user.isAdmin;.
Does hidden content still cost anything? Content that is not rendered costs nothing, because it is not in the page. Content hidden with CSS is still in the page, and its component still runs.
Can I render different components in a loop? Yes. Inside map, you can use a ternary or an object map to choose a component for each item, for example a Photo or a Video depending on the type field.
Is it fine to use switch? Yes. A switch before the return is good for many cases. Keep each case short, and move big pieces into their own components.
Your task
- Make a
LoginButtonthat shows “Log in” when signed out and “Log out” when signed in, using a ternary and state. - Make a
Noticecomponent that returnsnullwhen itsmessageprop is empty. - Make a
UserListthat shows Loading, an error message, an empty message, or the list, depending on three props. - Test the zero trap: show a count with
count && ...and then fix it.
How to check it worked
- Each situation shows the right screen when you change the props by hand.
- No stray
0appears on the page. - No error in the console when the data is empty.
Summary
- Conditional rendering is plain JavaScript:
if, ternary?:and&&. - Use early returns for loading, error and empty screens.
- Make the left side of
&&a real true or false to avoid the stray0. - Return
nullto show nothing, and use?.to read values that may be missing.