Conditional Rendering
Rendering UI conditionally with &&, ternary, early return null, JSX variables, and the 0-renders bug.
🧑🏫 Sabse pehle — simple mein samjho#
UI mein bhi if-else chalta hai: jab kuch sach ho tabhi dikhao. Do common tareeke — {condition && <X/>} (condition sach to X dikhao) aur cond ? <A/> : <B/> (sach to A, warna B). Jaise ghar pe "agar mehmaan aaye to hi chai banao" — condition poori to hi kaam. Ek gotcha: {count && <X/>} mein jab count 0 ho to screen pe 0 chhap jata hai, isliye count > 0 && ... likho.
function Cart({ count }) {
return (
<div>
{count > 0 && <p>{count} items</p>} {/* sach to hi dikhega */}
{count > 0 ? <button>Checkout</button> : <p>Cart khaali hai</p>}
</div>
);
}
Yaad rakho: && se dikhao/chhupao, ? : se do mein se ek choose karo — aur 0 wale gotcha se bacho.
The core idea#
JSX is just expressions, so conditional rendering is ordinary JS producing React nodes. React renders null, undefined, false, and true as nothing — but not 0 or "" (those are printed). 🎯
function Notifications({ items }) {
if (!items) return null; // early return: render nothing
const empty = items.length === 0;
return (
<div>
{empty ? <Empty /> : <List items={items} />} {/* ternary: either/or */}
{items.length > 0 && <Badge n={items.length} />} {/* && : maybe */}
</div>
);
}
Techniques compared#
| Technique | Use when | Note |
|---|---|---|
cond && <X/> |
Show X or nothing | ⚠️ guard the left side (see below) |
cond ? <A/> : <B/> |
One of two branches | Nesting ternaries hurts readability |
if (...) return null |
Whole component renders nothing | 🟢 cleanest for guard clauses |
| JSX in a variable | Complex multi-branch logic | Compute above return, keep JSX flat |
// 🟢 Variable holding JSX keeps the returned tree readable
let content;
if (status === "loading") content = <Spinner />;
else if (status === "error") content = <Error />;
else content = <Data value={data} />;
return <section>{content}</section>;
Real-world example: a Flipkart/Myntra-style navbar 🎯#
A header that swaps Login for a Profile menu, plus a cart badge, exercises all three techniques at once:
function ProfileMenu({ user }) {
if (!user) return null; // early return: nothing to render pre-login
return (
<div className="profile-menu">
<Avatar user={user} />
<button onClick={logout}>Logout</button>
</div>
);
}
function Navbar({ user, cartCount }) {
return (
<nav>
<Logo />
{/* ternary: exactly one of two branches, never both */}
{user ? <ProfileMenu user={user} /> : <button onClick={openLogin}>Login</button>}
{/* && : show the badge, or nothing — but watch what "nothing" means for 0 */}
{cartCount && <span className="badge">{cartCount}</span>}
</nav>
);
}
When the cart is empty, cartCount is 0 — a real, valid number, but falsy. {cartCount && <span>...} then renders the literal digit 0 as a stray badge next to the cart icon, a bug that's easy to ship on exactly this kind of header:
// ⚠️ empty cart still shows a naked "0" pill on the navbar
{cartCount && <span className="badge">{cartCount}</span>}
// 🟢 coerce to a real boolean first
{cartCount > 0 && <span className="badge">{cartCount}</span>}
flowchart TD
A["Navbar renders"] --> B{"user present?"}
B -->|"yes"| C["Ternary true branch: ProfileMenu (Avatar + Logout)"]
B -->|"no"| D["Ternary false branch: Login button"]
C --> E{"cartCount value"}
D --> E
E -->|"0 (falsy, but a real number)"| F["cartCount && <Badge/> prints literal '0' ⚠️"]
E -->|"greater than 0"| G["cartCount && <Badge/> renders the badge 🟢"]
E -->|"guarded as cartCount > 0"| H["Real boolean: badge or nothing, never a stray 0 🟢"]
⚠️ The count && <X/> bug#
&& returns its left operand when that operand is falsy. If the left side is the number 0, React renders the 0 on screen instead of nothing.
{count && <Cart />} // ⚠️ when count === 0 → renders literal "0"
{count > 0 && <Cart />} // 🟢 coerce to a real boolean
{count ? <Cart /> : null} // 🟢 ternary is unambiguous
{!!items.length && <List/>}// 🟢 double-bang forces boolean
Same trap with empty strings inside && chains — always ensure the left operand is a genuine boolean.
flowchart TD
A["Expression in JSX"] --> B{"Value type?"}
B -->|"null / undefined / true / false"| C["Renders nothing"]
B -->|"0 or empty string"| D["Renders the value ⚠️"]
B -->|"React element"| E["Renders the element"]
Interview Q&A#
Q1. Why does {count && <X/>} render 0 when count is zero?
&& short-circuits and returns the left operand when it is falsy. 0 is falsy but is a valid React child, so React prints 0. Use count > 0 && or a ternary.
Q2. Which falsy values does React skip rendering?
null, undefined, true, and false render as nothing. 0 and "" are rendered as text.
Q3. Ternary vs && — when do you pick each?
Use && for "show this or nothing", and a ternary for "show A or B". A ternary is also the safe choice when the condition might be a number.
Q4. Is early return null different from returning false?
Both render nothing. return null is the idiomatic, explicit signal that a component intentionally renders no output; returning false works but reads as accidental.