Chapter 8 of 20 · React for Beginners — Complete Free Tutorial
Conditional Rendering
Real interfaces in the React for Beginners series hide, swap and reveal elements depending on the situation: a spinner while loading, a login form when signed out, a badge only for admins. Because JSX is JavaScript, you already own every tool you need — if, the ternary operator, logical && — and this chapter shows where each one fits.
The && guard
When something should render only when a condition is true, put the condition and the markup on either side of &&. If the condition is false, React renders nothing:
function Notice({ unread }) {
return (
<div>
<p>Inbox</p>
{unread > 0 && <span className="badge">{unread} new</span>}
</div>
);
}
Expected output: with unread = 3 the badge shows 3 new; with unread = 0 no badge element exists at all — not an empty badge, nothing.
One trap to memorise: && renders the left operand's value when it is truthy. {count && count} with count = 0 prints 0 on the page, because 0 is a renderable value. Guard with an explicit comparison: {count > 0 && count}.
The ternary operator
When there are two alternatives — loading or data, name or fallback — the conditional (ternary) operator keeps both visible in one expression:
function Greeting({ user }) {
return (
<p>
{user ? `Welcome back, ${user.name}` : 'Please sign in'}
</p>
);
}
Expected output: Welcome back, Ada when a user object exists, Please sign in when it is null. The shape reads left to right: condition, then value if true, then value if false.
Early returns
For whole-section decisions, an early return before the main JSX keeps the common path uncluttered — the component simply returns null, and React renders nothing for it:
function Sidebar({ visible }) {
if (!visible) return null;
return <aside className="sidebar">Navigation here</aside>;
}
Expected output: visible = false leaves the page with no <aside> in the DOM; true renders it normally. Use this whenever one flag would otherwise wrap the entire return value in a ternary.
Choosing a pattern
| Situation | Pattern | Example |
|---|---|---|
| Show an extra element when true | && | {isAdmin && <AdminPanel />} |
| Pick one of two alternatives | Ternary | {loading ? spinner : list} |
| Bail out entirely | Early return null | Hidden routes, empty guards |
| Three or more branches | if / switch above the return, or a lookup map | Status → component tables |
Extracting small components
When a conditional grows teeth — nested ternaries, several flags — stop nesting markup and extract. A tiny component with its own early reads beats a five-level expression every time:
function Status({ state }) {
if (state === 'loading') return <p role="status">Loading…</p>;
if (state === 'error') return <p className="error">Something went wrong</p>;
return <p className="ok">Up to date</p>;
}
Expected output: one of the three messages, selected by a single prop — and callers never see the branching logic. role="status" announces loading text to screen readers, because invisible-until-changed UI should still be announced.
Conditional attributes and classes
The same techniques apply to props. A common idiom builds the className string from a condition, which you will use constantly once styling arrives in chapter 17:
<button className={isSelected ? 'tab is-active' : 'tab'}>
{label}
</button>
Expected output: the same button element with either one class name or two — the active state toggles purely from data, with no manual class manipulation anywhere in your code.
Conditional rendering also composes with lists and effects: show a spinner while a request is in flight, swap in the results when it resolves, and render an error message if it fails. Each of those is just another branch driven by state, exactly like the patterns above.
Common mistakes
- Rendering
0by accident —{count && …}shows a literal zero; compare explicitly. - Assignment instead of comparison —
{done = true && …}assigns in an expression and breaks; use===. - Deeply nested ternaries — if you cannot read it aloud, extract a component or an early return.
- Returning multiple roots — branches must each produce one element (or a fragment).
- Forgetting the false branch — a ternary without its third part yields
undefined, which React never renders; harmless, but easy to misread as a bug.
Practice checklist
- Render a badge with
&&for three different unread counts, including zero. - Build the signed-in/signed-out greeting with a ternary.
- Convert one nested-ternary mess into an early-return component.
- Create a status indicator that switches between loading, error and success.
- Verify in dev tools that hidden branches leave no elements in the DOM.
One value per condition is useful — lists need the same treatment for many items. Next: Rendering Lists and Keys.
Frequently Asked Questions
React is a JavaScript library for building user interfaces from reusable components. It manages how your UI updates when data changes, so you describe what the screen should look like and React performs the efficient DOM updates. It is one of the most in-demand frontend skills and powers products from Netflix to Instagram, which makes it an excellent next step after core JavaScript.
You should be comfortable with functions, arrays and objects (map, filter, spread), destructuring, modules and basic async/await. React itself is written in plain JavaScript — JSX is a syntax layer on top. If any of those feel shaky, revisit the JavaScript fundamentals first and this series will go much faster.
React is a library focused only on the UI layer — you choose your own router, data layer and tooling. Angular is a full framework that ships routing, forms, HTTP client and testing conventions as one opinionated package. React's flexibility and huge ecosystem make it the common choice for teams that want to compose their own stack.
A component is a reusable function that returns UI. It receives input through props, keeps private data in state, and can render other components. Pages are composed by nesting small components (navbar, card list, footer) instead of one giant file, which keeps code testable and easy to change.
JSX is a syntax extension that looks like HTML but compiles to React's create() calls — it is a description of UI, not markup the browser parses. Small differences matter: class becomes className, style takes an object, and you embed JavaScript expressions inside curly braces. Once compiled, React turns that description into real DOM nodes.
Props are inputs passed from a parent — they are read-only inside the child, like function arguments. State is private, mutable data owned by a component; updating it triggers a re-render. The rule of thumb: values that come from outside the component are props; values that change over the component's lifetime are state.
Rendering means calling your component function to produce a description of the UI for the current state and props. It does not always mean DOM work — React compares the new description with the previous one (reconciliation) and applies only the differences to the real DOM. This is why updating state 100 times does not mean 100 full page rebuilds.
An effect runs after the component has committed to the screen — after render, not during it. You list dependencies in an array, and React re-runs the effect only when one of them changes. If the effect returns a cleanup function, React runs it before the next re-run and on unmount, which is where you cancel timers, abort fetches and remove listeners.
Use Vite. Create React App is effectively in maintenance mode, while Vite starts instantly (native ES modules) and builds fast, and it is the default choice for new React projects. This series uses Vite for every example — you only need Node.js installed to follow along.
React apps compile to static files (HTML, CSS and JavaScript), so any static host works: Netlify, Vercel, GitHub Pages or Cloudflare Pages. Run the production build, upload the dist folder, and configure a single-page-application fallback so unknown paths load index.html — routing chapters explain why that fallback is required.