Conditional Rendering
One of the most powerful aspects of React is that your UI is just JavaScript. That means you can use all of JavaScript's control flow — if, else, ternaries, logical operators — to decide what to render. React doesn't have a special template directive like v-if or *ngIf; you use plain JavaScript expressions instead.
if/else Before the Return
The simplest and most readable approach is an if statement above the return. Extract complex conditions here to keep your JSX clean:
function UserGreeting({ user, isLoading }) {
if (isLoading) {
return <p>Loading...</p>
}
if (!user) {
return <p>Please log in.</p>
}
return <h1>Welcome back, {user.name}!</h1>
}This is excellent for early returns — guard clauses that bail out before the main render logic. Each condition is easy to read and debug.
Ternary Operator in JSX
Inside JSX you can't use if statements (they're not expressions). The ternary operator condition ? ifTrue : ifFalse works because it's an expression that produces a value:
function SubscribeButton({ isSubscribed, onToggle }) {
return (
<button onClick={onToggle}>
{isSubscribed ? 'Unsubscribe' : 'Subscribe'}
</button>
)
}
// Ternary can also switch entire elements
function StatusBadge({ status }) {
return (
<span className="badge">
{status === 'online'
? <span className="green">● Online</span>
: <span className="red">● Offline</span>
}
</span>
)
}The && Operator (Single-Branch Rendering)
When you only want to render something if a condition is true — and render nothing if it's false — use the && operator:
function Notification({ message, count }) {
return (
<div>
<h2>Inbox</h2>
{count > 0 && <p>You have {count} unread messages.</p>}
{message && <div className="alert">{message}</div>}
</div>
)
}
// When count=0: <p> is not rendered
// When count=3: renders "You have 3 unread messages."Nullish Coalescing (??) for Fallbacks
?? returns its right side only when the left side is null or undefined (not other falsy values like 0 or ""):
function UserProfile({ user }) {
return (
<div>
<h2>{user.displayName ?? user.email}</h2>
<p>{user.bio ?? 'No bio provided.'}</p>
<p>Posts: {user.postCount ?? 0}</p>
</div>
)
}
// user.postCount = 0 → shows "Posts: 0" (correct, 0 is valid)
// user.postCount = null → shows "Posts: 0" (correct, falls back)
// Whereas user.postCount || 0 would show "Posts: 0" for postCount=0 too
// but would incorrectly show 0 for postCount="" (empty string)switch for Multiple Conditions
When you have more than two branches, a switch statement above the return is cleaner than nested ternaries:
function RequestStatus({ status }) {
switch (status) {
case 'idle':
return null
case 'loading':
return <Spinner />
case 'success':
return <SuccessMessage />
case 'error':
return <ErrorMessage />
default:
return <p>Unknown status: {status}</p>
}
}
// Or with an object lookup for compact inline logic
const STATUS_ICON = {
loading: '⏳',
success: '✓',
error: '✗',
idle: '–',
}
function StatusIcon({ status }) {
return <span>{STATUS_ICON[status] ?? '?'}</span>
}Rendering null (Render Nothing)
Returning null from a component (or including null in JSX) renders nothing — no DOM node, no empty element. This is React's explicit "render nothing" value.
// A component that renders nothing when not visible
function Toast({ message, visible }) {
if (!visible) return null // component renders nothing
return (
<div className="toast">
{message}
</div>
)
}
// null in JSX expressions also renders nothing
function Panel({ showFooter, children }) {
return (
<div>
{children}
{showFooter ? <footer>Footer content</footer> : null}
</div>
)
}Extracting Conditional JSX to Variables
When conditional logic gets complex, extract it to a variable before the return statement to keep your JSX readable:
function ProductCard({ product, user }) {
// Compute what to show before the return
let priceDisplay
if (!user) {
priceDisplay = <span>Log in to see price</span>
} else if (user.isPremium) {
priceDisplay = <span className="premium">${product.premiumPrice}</span>
} else {
priceDisplay = <span>${product.regularPrice}</span>
}
return (
<div className="product-card">
<img src={product.image} alt={product.name} />
<h3>{product.name}</h3>
{priceDisplay}
</div>
)
}Choosing the Right Pattern
Early return / if-else before return — best for component-level guards, loading states, error states
Ternary
? :— best for two-branch inline JSX choices&&operator — best for single-branch show/hide (but watch the 0 gotcha)??operator — best for null/undefined fallback valuesswitchstatement — best for 3+ named conditionsVariable extraction — best when the conditional logic is complex or reused