Command Palette

Search for a command to run...

Hectal
PHASE 3Beginner ~32 min· topic 1 of 4

Topic 3.1

Conditional Rendering

In one line

Conditional rendering means a component shows different UI for different data, using plain JavaScript: an if with an early return, the ternary ? :, &&, returning null, conditional props and classes, and picking a component from a variable or an object map.

Think of it like this

A shop door sign. The shopkeeper doesn't paint a new door every evening. The sign has two sides, OPEN and CLOSED, and the time of day decides which side faces the street. A React component works the same way: it has all the possible pictures inside it, and the data decides which one is shown right now.

Words you'll meet

New words in this topic, in plain English. Come back here whenever one feels fuzzy.

Conditional rendering
Showing different UI depending on data, using if, ? : or &&.
Condition
A value or test that is true or false, such as isLoggedIn or count > 0.
Early return (guard clause)
Checking a special case at the top of a function and returning right away, so the rest only handles the normal case.
Ternary operator
condition ? a : b: gives a when the condition is true, b when it is false.
Logical AND (&&)
a && b gives a if a is falsy, otherwise b. In JSX it means "show this or nothing".
Falsy
A value JavaScript treats as false: false, 0, "", null, undefined and NaN.
null
A value meaning "nothing". A component that returns null shows nothing.
Object map (lookup table)
An object that maps names to values, like { grid: GridView, list: ListView }, used instead of a long if/else chain.

Step by step

01Start with the special case: an early return

An inbox makes no sense without a signed-in user. Handle that first and leave. Everything after the if can assume user exists.

Inbox.jsxwhole filejsx
function Inbox({ user }) {
  if (!user) {
    return <p>Please sign in to see your messages.</p>;
  }
  return <h2>Hello, {user.name}!</h2>;
}

02Pick one of two inside JSX: a ternary

When only a small part changes, put the choice right where it shows. A ternary always produces one of its two values.

Inbox.jsxwhole filejsx
<h2>{user.isAdmin ? "Admin inbox" : "Your inbox"}</h2>

03Show or hide one thing: && with a real boolean

To show something only sometimes, use &&. Make the left side a true comparison (> 0), never a bare number, or an empty count will put a 0 on the page.

Inbox.jsxwhole filejsx
{unread > 0 && <p className="badge">{unread} unread</p>}

04How React treats each value

Whatever a condition produces ends up as a child in JSX. This table is what decides what you see.

How React treats each valuediagram
Rendering diagram…

05Make attributes and classes conditional

Attributes take expressions too. Use a ternary, and undefined when the attribute should not exist at all.

SaveButton.jsxwhole filejsx
<button
  disabled={!changed}
  className={changed ? "save ready" : "save"}
  title={changed ? undefined : "Nothing to save yet"}
>
  Save
</button>

06Many choices: a variable or an object map

With three or more cases, decide before the return. An object map from names to components is the neatest: the JSX stays one line, and adding a case is one line of data.

Gallery.jsxwhole filejsx
const VIEWS = { grid: GridView, list: ListView, count: CountView };

function Gallery({ mode, photos }) {
  const View = VIEWS[mode]; // capital V: JSX needs it
  return <View photos={photos} />;
}

Try it yourself

  1. 1

    Make yourself an admin

    In "Four ways to choose", change isAdmin: false to isAdmin: true. Predict which heading appears after you sign in, then check.

  2. 2

    See the gotcha disappear

    In "The 0 && gotcha", change Cart to use !!items.length &&. Predict the console line first. (Cart shows: "": !!0 is false, and React shows nothing for false.)

  3. 3

    Add a view with one line

    In the gallery, write a ShoutView that renders the photo names in capitals, and add shout: ShoutView to VIEWS. A new button appears by itself, because the buttons are made from Object.keys(VIEWS).

  4. 4

    Hide in the parent instead

    In the first example, remove the if from Banner and write {signedIn && <Banner />} in App instead. The page looks the same. What is the difference? (Now Banner isn't called at all while hidden.)

Code & diagrams

Four ways to choose what to show New tab

Click **Sign in**, then **New message** a few times. The early return, the ternary, `&&` and `return null` each decide one part of the screen.

Preview

Press Run to see the page.

Console

Nothing logged yet.
The 0 && gotcha New tab

The first box shows a lonely **0**. The fix is a real comparison on the left of `&&`.

Preview

Press Run to see the page.

Console

Nothing logged yet.

Expected console output

Cart shows: "0"
FixedCart shows: ""
Pick a component from an object map New tab

The buttons get a conditional class and `aria-pressed`, and `VIEWS[mode]` picks which component renders. Try adding a fourth view.

Preview

Press Run to see the page.

Console

Nothing logged yet.
Which tool for which choicediagram
Rendering diagram…

Break it on purpose

Errors are the best teachers. Make each change, read the error, guess what went wrong, then reveal the answer.

Break #1

Use && for a normal attribute

In the gallery, replace the button's className with className={name === mode && "tab active"}.

terminal
$ Console
── what you'll see ──
Received `false` for a non-boolean attribute `className`.
 
If you want to write it to the DOM, pass a string instead: className="false" or className={value.toString()}.
 
If you used to conditionally omit it with className={condition && value}, pass className={condition ? value : undefined} instead.

Break #2

Name the chosen component with a small letter

In the gallery, rename const View to const view and render <view photos={photos} />.

terminal
$ Preview
── what you'll see ──
The buttons still work, but no photos appear under them for any mode.

Myth vs fact

Myth

React needs special syntax like v-if for conditions.

Fact

React uses plain JavaScript: if, ? :, && and variables. There is nothing extra to learn, only JavaScript's rules about which values are falsy.

Myth

{count && <Thing />} is always safe.

Fact

When count is 0, the expression gives 0, and React renders numbers. Use count > 0 &&.

Myth

A component that returns null doesn't run.

Fact

It runs every time its parent renders: its hooks run and its state is kept. It just adds nothing to the page. To skip running it, don't render it from the parent.

Myth

Hiding something with a condition is the same as hiding it with CSS.

Fact

A condition removes the elements from the DOM and, when the component itself is removed, throws away its state. CSS (display: none or the hidden attribute) keeps the DOM and state. React 19.2's <Activity mode="hidden"> hides while keeping state (Topic 16.10).

Pro corner

Extra depth for experienced readers. New to this? Skip it for now and come back later.

  • ▸

    When a ternary swaps between two different component types at the same spot ({isAdmin ? <AdminForm /> : <UserForm />}), React unmounts one and mounts the other, so all state and DOM inside are lost. Two of the same type at the same spot ({isAdmin ? <Form role="admin" /> : <Form role="user" />}) keep their state, because React matches by type and position. This is the reconciliation rule you'll study in Topics 6.4 and 16.2.

  • ▸

    {cond && <A />} leaves a hole at that position when false, so siblings after it keep their positions and their state. That's why React handles conditional children without keys: a false or null child still takes up its slot in the children array.

  • ▸

    Never call a hook inside a condition (if (open) { useState(...) }). Hooks must run in the same order every render. Put the condition inside the JSX or inside the hook instead (Topic 4.3).

  • ▸

    An object map of components should be created outside the component (module level). Creating const VIEWS = { ... } with components defined inside the render would make new component types every render and reset their state each time (Topic 2.1).

Remember this

  1. 1

    Conditional rendering means returning different JSX depending on a condition (a value that is true or false, such as isLoggedIn or items.length > 0). React has no special v-if or *ngIf syntax. You use the JavaScript you already know: if, the ternary operator (condition ? a : b) and the logical AND operator (&&). The only rule to remember is the one from Topic 1.3: inside JSX curly braces you may write an expression (something that produces a value), not a statement (an instruction like if or for). So if goes *before* the return, and ? : and && go *inside* the JSX.

  2. 2

    If with an early return. When a whole component looks completely different in some case, check that case first and return straight away: if (!user) return <p>Please sign in</p>;. The code below it only runs for the normal case, so it can safely use user.name. This pattern is called a guard clause. It keeps the main JSX flat and readable instead of wrapping everything in one big condition.

  3. 3

    Ternary: this or that. {isAdmin ? <AdminPanel /> : <UserPanel />} shows exactly one of two things. Use it for small choices inside JSX: a label ({done ? "Done" : "To do"}), an icon, one of two components. Nested ternaries (a ? x : b ? y : z) work but become hard to read quickly; past two levels, move the choice into a variable or an object map (below).

  4. 4

    &&: something or nothing. {unread > 0 && <Badge />} shows the badge when the left side is true and nothing otherwise. It works because JavaScript's a && b gives back a when a is falsy (a value that counts as false: false, 0, "", null, undefined, NaN), and gives back b otherwise. React renders nothing for false, null, undefined and true, but it does render numbers, including 0. So {items.length && <List />} shows a stray 0 on the page when the array is empty. Always make the left side a real boolean: items.length > 0 &&, !!items.length &&, or Boolean(items.length) &&.

  5. 5

    Returning null. A component may return null to render nothing at all: if (!show) return null;. The component still runs: React calls it, its hooks run and its state is kept. It only puts nothing on the screen. Since React 18 returning undefined is also allowed (React 17 threw an error), but null says "nothing, on purpose" more clearly. Whether to hide something inside the child (return null) or in the parent ({show && <Child />}) is a design choice: the parent version doesn't run the child at all, and its state is thrown away when it is hidden.

  6. 6

    Conditional props and classes. Conditions work for attributes too: disabled={!agreed}, aria-expanded={open}, className={active ? "tab active" : "tab"}. To leave an attribute out completely, pass undefined (title={saved ? "Saved" : undefined}); React then doesn't write it to the DOM. Don't use && for non-boolean attributes: title={saved && "Saved"} passes false when not saved, and React warns about it. For several optional classes, build a list and join it: ["tab", active && "active", error && "error"].filter(Boolean).join(" "). The tiny clsx package does exactly this (Topic 1.5 and Phase 11).

  7. 7

    Choosing a component with a variable or an object map. For more than two choices, decide before the JSX. Either assign JSX to a variable (let content; if (status === "loading") content = <Spinner />; else if (...) ...), or keep a lookup object from names to components: const VIEWS = { grid: GridView, list: ListView } and then const View = VIEWS[mode]; return <View photos={photos} />;. The variable must start with a capital letter (View, not view), because JSX treats lowercase names as HTML tags. An object map turns a long if/else chain into data: adding a view is one new line. Note that switching to a different component type throws away the old one's state (Topic 6.4).

Explain it without notes

01

Why can't you write if directly inside JSX curly braces, and what do you use instead?

02

Explain the 0 && bug and two ways to fix it.

03

What happens when a component returns null? How is that different from not rendering it in the parent?

04

How do you choose between many components without a long chain of ternaries?

05

How do you make an attribute or a class conditional, and how do you leave an attribute out completely?

Practice

01

Write a Status component that takes an online boolean and shows a green Online or a grey Offline label, using a ternary for both the text and the class.

02

Write a Notifications component that takes count and shows You have N new notifications only when count is above zero, and null otherwise. Make sure count = 0 shows nothing at all.

03

Write a Weather component that takes kind ("sun", "rain" or "snow") and renders <Sun />, <Rain /> or <Snow /> using an object map, with a fallback <p>Unknown weather</p> for any other value.

Trade-offs

  • ↔

    Early returns keep the main JSX simple but spread the output over several returns; for a component with many states, an object map or a small switch keeps every case visible in one place.

  • ↔

    Removing UI with a condition frees its DOM and state (good for memory, bad if the user expects their half-typed text to survive). Hiding with CSS or <Activity> keeps them, at the cost of keeping them in memory.

Done when you can

  • I can use an early return for a special case.

  • I can choose between two things with a ternary and show-or-nothing with &&.

  • I can explain and avoid the 0 && bug.

  • I know a component may return null and that it still runs.

  • I can make attributes and classes conditional and omit an attribute with undefined.

  • I can choose a component from an object map with a capitalised variable.