Conditional rendering
Showing UI only under some condition is everyday React. Three patterns cover nearly every case.
Ternary, choose between two things:
<p>{isSaved ? "Saved ✓" : "Unsaved changes"}</p>Logical &&, show or nothing:
{error && <p className="error">{error}</p>}In Advanced JavaScript you learned && short-circuits: if the left side is falsy it returns the left side, otherwise it returns the right side. React renders false, null, and undefined as nothing, so a falsy left side hides the element.
Early return, skip the whole component:
function Banner({ show }) { if (!show) return null; return <div className="banner">Sale ends today!</div>; }
Returning null renders nothing. Full statements like if are allowed here because we are above the JSX, in plain function-body land.
The zero gotcha
React renders false as nothing, but it renders the number 0 as a visible "0". That makes one && pattern dangerous:
{unread && <p>You have mail</p>}If unread is 0, the expression evaluates to 0, and a stray 0 appears on screen. Fix it by making the left side a real boolean:
{unread > 0 && <p>You have mail</p>}The zero gotcha in plain JavaScript
&& returns its left side when that side is falsy, so a zero comes straight through, while a comparison returns a real boolean.
console.log(0 && "You have mail"); console.log(3 && "You have mail"); console.log(0 > 0 && "You have mail"); console.log(3 > 0 && "You have mail");
Output
0 You have mail false You have mail
The key fact is that && does not return true or false, it returns one of its two operands. That is the Advanced JavaScript short-circuit rule, and it is the entire cause of the gotcha.
React renders false as nothing and renders 0 as the character 0, so the first line would put a stray zero on the page and the third would render nothing. Prefer boolean left sides and the problem cannot arise.
The same trap has a string version worth expecting. An empty string is falsy, so {name && <p>{name}</p>} renders nothing when name is "", which happens to be the desired behavior and is an accident rather than a decision.
Note that the fix is not Boolean(unread) && ..., though that works. Writing unread > 0 says what the condition actually is, which is clearer to the next reader than a coercion wrapped around a number.
Reading a length-based condition
<div>
{items.length && <p>{items.length} items</p>}
</div>With an empty items, this renders a div containing the text 0.
items.length is 0, which is falsy, so && returns 0 itself, and React renders the number 0 as text. The paragraph never appears, and a bare zero does.
Writing items.length > 0 && ... renders nothing instead, because the comparison produces false and React renders false as nothing.
This is the single most common form of the gotcha in real code, because .length is the natural thing to test and it is a number rather than a boolean. Seeing an unexplained 0 on a page is close to a signature for this bug.
Note that the outer div still renders in both versions, so the fix removes the stray character and not the wrapper. Removing the wrapper too would need the early-return pattern, returning null from the component when there is nothing to show.
The value that renders nothing
The blank is filled with null, so the line reads if (!user) return null;.
React renders null, and also false and undefined, as nothing at all, producing no DOM node in that position.
The near-misses are instructive:
| Returned value | What renders |
|---|---|
null | nothing, the idiomatic choice |
false | nothing, though it reads oddly |
undefined | nothing, and React warns for a missing return |
"" | an empty text node |
0 | a visible zero |
null is the idiomatic answer because it says "deliberately nothing" rather than arriving by accident. A component that falls off the end without a return yields undefined, and React treats that as a probable mistake and warns about it.
The early return also has a practical advantage over wrapping the whole body in a ternary. Everything below the guard can assume user exists, so the rest of the component reads without conditionals, which is the same guard-clause style as the empty-input checks from testing work.