← React for Beginners

Showing things conditionally

Lesson 06 of 12 · 6 min

This is the short one. There is no new React in it at all - conditional rendering is ordinary JavaScript in the braces you already know about. What is worth your attention is which form to reach for, and one specific way the tidiest of them goes wrong.

Just use an if

The braces in JSX take an expression, and if is a statement, so this does not work:

<p>{if (note.pinned) { ... }}</p>   {/* no */}

But nothing stops you writing an if in the ordinary part of the function, before the return:

function Note({ note }) {
  if (note.hidden) {
    return null;
  }

  return (
    <article>
      <h3>{note.title}</h3>
      <p>{note.body}</p>
    </article>
  );
}

return null means “render nothing here”. Not an empty element, nothing at all. It is the right answer whenever a whole component should be absent, and an early return keeps the condition at the top where it is easy to see.

For a component that renders one of two entirely different things, plain if/else is still the clearest thing you can write:

function NoteList({ notes }) {
  if (notes.length === 0) {
    return <p>No notes yet.</p>;
  }

  return (
    <div>
      {notes.map((note) => (
        <Note key={note.id} note={note} />
      ))}
    </div>
  );
}

Reach for the fancier forms when the choice is inside the markup and pulling it out would mean duplicating everything around it.

A ternary, for one thing or another

Inside JSX, condition ? a : b is an expression, so it goes in braces:

<h2>{note.title ? note.title : "Untitled"}</h2>

That particular example is better written {note.title || "Untitled"}, but the shape is the point: exactly one of two things renders. Ternaries work on whole elements too:

<div>
  {note.pinned ? <strong>Pinned</strong> : <span>Not pinned</span>}
</div>

They nest, and you should resist. A ternary inside a ternary inside JSX is the point at which everybody stops being able to read your component. Pull it out into a variable above the return, or into its own component.

&&, for one thing or nothing

Very often there is no “or else” - you either show the badge or you do not:

<div>
  {note.pinned && <strong>Pinned</strong>}
</div>

This works because of what && actually does in JavaScript. It is not “and” in the grammatical sense; it returns the left value if that value is falsy, and otherwise the right one. So when note.pinned is true the expression evaluates to the <strong> element, and when it is false the expression evaluates to false - and React renders false as nothing.

That last part is the rule the next section turns on. In JSX:

  • null, undefined, true and false all render nothing
  • a string or a number renders itself
  • an array renders each item in turn, which is why .map() worked in the last lesson

The zero

Here is a perfectly reasonable-looking line:

{notes.length && <p>You have notes.</p>}

When notes is empty, notes.length is 0. && returns the left value because 0 is falsy - so the expression evaluates to the number 0. And a number renders itself.

You get a stray 0 on the page. There is no error and no warning, just a zero sitting where you expected nothing:

0

It is the single most common React bug that makes a beginner doubt their own eyes, and it comes entirely from && returning a value rather than a boolean.

The fix is to give && an actual boolean on the left:

{notes.length > 0 && <p>You have notes.</p>}

Every falsy value except 0 and NaN happens to render as nothing, so this only ever bites with numbers, which is why it catches people out. array.length is the one you will hit, over and over.

Get in the habit of writing the comparison. notes.length > 0 && is one character longer than notes.length && and it can never surprise you.

Which to use

  • A whole component should not render: return null.
  • Two entirely different outcomes: if/else before the return.
  • One of two things, inline in markup: a ternary.
  • Something or nothing, inline in markup: &&, with a real boolean on the left.

Recap

Conditional rendering is expressions in braces, plus knowing what React does with the result. null, undefined, true and false render nothing, numbers and strings render themselves, and that last fact is why count && <p/> prints a zero while count > 0 && <p/> does not.

Next: everything so far has drawn a page from data that never changes. Time to make it respond.

Optional Checkpoint: the first half 10 questions on lessons 1–6. Nothing is stored and nothing is sent - it is a self-check, and every answer links back to the lesson it came from.