Setting up a React project with Vite
The mental model: how React renders (2)
Sometimes you want to show something only under certain conditions — a loading spinner while data is fetching, an error message when something goes wrong, a logout button only when the user is logged in. React has no special template syntax for this. You just use regular JavaScript inside {}.
There are four patterns worth knowing. Each fits a different situation.
https://www.youtube.com/watch?v=XvURBpFxdGw
{isLoggedIn ? <LogoutButton /> : <LoginButton />}
Use this when both branches matter — when you want to show one thing or another.
{hasError && <ErrorMessage />}
{cartItems.length > 0 && <Checkout />}
Use this when you want to render something only if a condition is true, and nothing otherwise.
<aside> ⚠️
Warning
&& returns the left side if it's falsy. If that left side is the number 0, React renders the literal character "0" on screen:
{cartItems.length && <Checkout />} // Renders "0" when the cart is empty
Always use an explicit boolean comparison:
{cartItems.length > 0 && <Checkout />} // ✅
This is one of the most common gotchas in React. You'll hit it at least once.
</aside>
When a component has several different states to handle — loading, error, empty, success — early returns keep the code clean and readable:
function UserProfile({ user, isLoading, error }) {
if (isLoading) return <Spinner />;
if (error) return <ErrorMessage error={error} />;
if (!user) return <p>No user found.</p>;
return (
<div>
<h2>{user.name}</h2>
<p>{user.bio}</p>
</div>
);
}
Read top-to-bottom, return early on edge cases, render the happy path at the end. This is much cleaner than nesting ternaries inside the JSX.
<aside> 💡
Info
The loading/error/empty/success pattern you see above is the standard shape for any component that fetches data. You'll use it constantly once we get to data fetching in week 10 — the structure will already feel familiar.
</aside>
For switch-style logic with several possible values, compute the JSX before the return:
function StatusBadge({ status }) {
let badge;
if (status === 'online') {
badge = <span style={{ color: 'green' }}>🟢 Online</span>;
} else if (status === 'away') {
badge = <span style={{ color: 'orange' }}>🟡 Away</span>;
} else {
badge = <span style={{ color: 'gray' }}>⚪ Offline</span>;
}
return <div>Status: {badge}</div>;
}
When there are many possible values, an object lookup is often cleaner:
const STATUS_BADGES: Record<string, JSX.Element> = {
online: <span style={{ color: 'green' }}>🟢 Online</span>,
away: <span style={{ color: 'orange' }}>🟡 Away</span>,
offline: <span style={{ color: 'gray' }}>⚪ Offline</span>,
};
function StatusBadge({ status }: { status: string }) {
return <div>Status: {STATUS_BADGES[status] ?? STATUS_BADGES.offline}</div>;
}
?? is the nullish coalescing operator — it falls back to the right side when the left side is null or undefined. Here it handles any status value that isn't in the map.
A component can return null when it should render nothing at all:
function Notification({ message }: { message: string | null }) {
if (!message) return null;
return <div className="notification">{message}</div>;
}
The component still exists in the tree — it just produces no DOM output. This is different from not rendering the component at all, which matters when state or effects are involved (more on that in week 8).
<aside> ⌨️
Hands On
Build a WeatherCard component that takes a temperature prop typed as number | undefined. Render:
temperature is undefinedUse an early return for the no-data case and a variable for the temperature logic.
</aside>
interface GreetingProps {
isLoggedIn: boolean;
username: string | null;
unreadMessages: number;
}
function Greeting({ isLoggedIn, username, unreadMessages }: GreetingProps) {
if (!username) return <p>Loading...</p>;
return (
<div>
{isLoggedIn ? (
<h2>Welcome back, {username}!</h2>
) : (
<h2>Please log in.</h2>
)}
{isLoggedIn && unreadMessages > 0 && (
<p>
You have {unreadMessages} unread message{unreadMessages === 1 ? '' : 's'}.
</p>
)}
{isLoggedIn && <button>Logout</button>}
</div>
);
}
Three patterns in one component: early return for the loading state, ternary for the two-outcome greeting, && for the conditional elements. Each used where it fits.
<aside> ⌨️
Hands On
Build a UserList component with three props: users (array), isLoading (boolean), error (string or null). Use early returns to handle each edge case:
isLoading is trueerror is not nullStretch: build a PriceTag component that takes price and an optional discount. With a discount, show the original price struck through and the discounted price beside it. Without, just show the price.
</aside>
<aside> 🎉
Celebration
You now have four tools for conditional rendering and you know when to reach for each one. Combined with lists and props, you can build nearly any static UI in React.
</aside>
The HackYourFuture curriculum is licensed under CC BY-NC-SA 4.0 *https://hackyourfuture.net/*

Built with ❤️ by the HackYourFuture community · Thank you, contributors
Found a mistake or have a suggestion? Let us know in the feedback form.