React Conditional Rendering

Chapter 11 22 mins

Learning outcomes:

  1. What is conditional rendering
  2. Conditional rendering using if
  3. Using the logical AND (&&) operator
  4. Using the logical OR (||) operator
  5. Using the conditional operator (?:) operator
  6. Conditionally removing attributes

What is conditional rendering?

As we continue developing small and simple programs in React, we'll eventually land in a position where we wish to conditionally render stuff.

For example, we might want to display a question's correct answer when a given option is selected. Or we might want to show a loading indicator if a given piece of data hasn't loaded yet. Or, as another example, we might want to make a password field visible when the eye toggle is selected. And so on.

This manner of rendering stuff in React based on the outcome of a given condition is commonly referred to as conditional rendering.

In React, in particular in JSX, there are many conventions surrounding conditional rendering.

In the following sections, we take a look at these conventions but before that, let's take a quick look at the naive way of dealing with conditions in JavaScript, and thus in React as well — using if and else.

Conditional rendering using if

Let's consider a simple program to implement.

Suppose we have a component Greeting meant to greet the user with an <h1>. It has a showInfo Boolean prop specifying whether some extra piece of information should be shown along with the <h1>.

When we instantiate the component as follows, we expect the information to be shown since showInfo is true:

<Greeting name="Dennis" showInfo />

Remember that when an attribute is not given a value in JSX, like showInfo here, it automatically gets assigned the value true in the converted JavaScript.

Similarly, when we instantiate the component as follows, we expect the opposite — the information to be hidden:

<Greeting name="Dennis" />

Remember that when a prop is not provided to a React element, the access of that prop inside the component resolves to undefined. Basic JavaScript.

Now, let's think about how to implement this component.

A naive approach, using JavaScript's if statement, follows:

function Greeting({ name, showInfo }) {
   if (!showInfo) {
      return (
         <header>
            <h1>Hello {name}!</h1>
         </header>
      );
   }

   return (
      <header>
         <h1>Hello {name}!</h1>
         <p>This is some extra information shown.</p>
      </header>
   );
}

The code is a little verbose but it does its job.

When showInfo is not given (i.e. has a falsey value), the returned set of elements doesn't contain a <p> element:

function App() {
   return (
      <Greeting name="Dennis" />
   );
}

Live Example

Otherwise, the <p> comes after the <h1>:

function App() {
   return (
      <Greeting name="Dennis" showInfo />
   );
}

Live Example

Now, as you'd definitely agree, this approach doesn't make much sense because in both cases, we're returning, more or less, the same kind of elements except for the <p>. We're copy/pasting the set of elements and that's not desirable.

Imagine that we had 100 lines of JSX code for our set of elements, again with one conditional <p> in there; would it now make sense to copy/paste the code in two places, one without the <p> and one with it? Clearly not!

This approach of if is mostly used when a completely different value is meant to be returned by a component.

Let's see such an example.

In the following code, we have a different Greeting component where we don't return anything when the name prop is not provided (or explicitly undefined):

function Greeting({ name }) {
   if (name === undefined) {
      return null;
   }

   return (
      <h1>{name}</h1>
   );
}

Let's see what happens by instantiating Greeting without a name prop:

function App() {
   return (
      <Greeting/>
   );
}

Live Example

As can be seen in the linked page above, nothing is rendered — we get a blank page.

This is simply because name is not provided and, consequently, Greeting returns null which, as we learnt in the React JSX chapter, doesn't get rendered.

Anyways, coming back to our original discussion, of the if statement being used in a scenario with an almost similar set of returned elements in both cases (when the condition is met and when it ain't), we need a better approach here.

What we need is something that allows us to express the set of elements exactly once, with the conditional bits and pieces inlined into that set of elements. In other words, we need some way to only express the <p> element conditionally without affecting other elements.

This basically means that we ask for an expression to represent conditional code.

And the good news is that JavaScript ships with three operators out of the box to help us in this regard: logical AND (&&), logical OR (||), and the conditional operator (also known as the ternary operator).

Let's see how to work with these operators to conditionally render elements in React.

The logical AND (&&) operator

The logical AND (&&) operator evaluates its left operand and if it's truthy, resolves down to the the value of the right operand. Otherwise, when the left operand is falsey, it resolves down to that very operand.

This operator should be used whenever we have a value that dictates the rendering of some other piece of content, however the value itself couldn't be directly rendered.

Let's see an example.

We don't have to go far away in search for an example; our example is right in the previous section. That is, let's use the logical AND (&&) operator to conditionally render the <p> element in the Greeting component shown above.

Here's our code with &&:

function Greeting({ name, showInfo }) {
   return (
      <header>
         <h1>Hello {name}!</h1>
{showInfo && <p>This is some extra information shown.</p>} </header> ); }

Notice a couple of things here:

  • Firstly, we've removed the if statement since that isn't needed.
  • Secondly, the conditional <p> element has been inlined into the JSX code, all thanks to the logical AND operator.
  • And lastly, the entire logical AND expression is wrapped up in curly braces ({}). This is simply because the JSX parser expects JSX here but we wish to denote some JavaScript code — {} instructs the parser to treat whatever is inside it as JavaScript code.

Clearly, using logical AND (&&) leads to a much more leaner and neater code.

The logical AND (&&) operator should be used whenever we wish to render content based on the value of a given identifier, or else render nothing.

It's crucial to note the part 'render nothing' in the previous sentence. If we wish to render nothing when a given check isn't fulfilled, we seek the logical AND operator. If we wish to render something when the check isn't fulfilled, we seek the ternary operator (?:), as we shall see later on below.

Now, let's talk about the logical OR (||) operator.

The logical OR (||) operator

The logical OR (||) operator evaluates the left operand and if it's truthy, resolves down to it, or else resolves to the right operand.

This operator should be employed whenever we wish to use a default value in place of a given arbitrary value in the instance when that arbitrary value doesn't fulfill a given criteria (for e.g. maybe it's undefined).

Here's an example.

Suppose we redesign our Greeting component to now take the extra information in the form of an info prop, instead of the information being hardcoded into the JSX and put behind a showInfo condition.

In the scenario when info is not given or is falsey, we must show the default text 'This is the default info.' inside the <p> element. Otherwise, we must show the info itself, again inside the <p> element.

Now because we're talking about relying on a default value here when info is falsey, we seek the logical OR (||) operator:

function Greeting({ name, info }) {
   return (
      <header>
         <h1>Hello {name}!</h1>
<p>{info || 'This is the default info.'}</p> </header> ); }

Note that because the <p> element is needed in both the cases, it is outside the conditional.

Let's try instantiating this component with and without info.

First, without info:

function App() {
   return (
      <Greeting name="Dennis" />
   );
}

Live Example

And now with info:

function App() {
   return (
      <Greeting name="Dennis" info="Our own info." />
   );
}

Live Example

Super-duper amazing.

Why we didn't assign a default value while destructuring?

You might be wondering why we didn't assign a default value to info in the destructuring expression. Something like this:

function Greeting({ name, info =  'This is the default info.' }) {
   return (
      <header>
         <h1>Hello {name}!</h1>
         <p>{info}</p>
      </header>
   );
}

Let's see why we didn't use this for our problem.

Suppose a component instantiates Greeting and always sets info to either a string or the value null. There is never ever a case where the component doesn't provide the info prop — it provided 'always'.

Now, if we had the code above, with info assigned a default value in the destructuring construct, providing null would set info to null and then this would be rendered in the <p> element, leading to...you guessed it...nothing rendered:

function Greeting({ name, info =  'This is the default info.' }) {
   return (
      <header>
         <h1>Hello {name}!</h1>
         <p>{info}</p>
      </header>
   );
}
<Greeting name="Dennis" info={null} /> // Nothing rendered

But if we have the expression info || 'This is..., providing null to info would resort back to the default information text in the <p>:

function Greeting({ name, info }) {
   return (
      <header>
         <h1>Hello {name}!</h1>
         <p>{info || 'This is the default info.'}</p>
      </header>
   );
}
<Greeting name="Dennis" info={null} /> // 'This is the default info.' rendered

This is exactly what we'd ideally want.

Thus, to prevent the absence of information in case info is null, we stick to using the logical OR (||) operator with info directly in the <p> element.

Obviously, using default values in the destructuring would be perfectly alright in certain cases. But at least it wasn't in our case, and that was worth nothing.

Finally, let's now consider the third and last of the three operators used in conditional rendering in React: the conditional operator (?:).

The conditional (?:) operator

There's absolutely no guess work involved with the conditional operator (?:) as there might be with the logical AND (&&) and the logical OR (||) operators. (Well, honestly, there isn't really any guess work involved with the latter two as well.)

The conditional operator is just an expressional if...else.

When we have two different things to render, depending on the outcome of a condition, we should go for the conditional operator, hands-down.

Let's suppose our Greeting component takes the info prop in the form of an object whose text property contains the text to put inside the <p> element. So, if info is provided, info.text should be used inside the <p> or else the same old default information.

Now, since we have two different things to do in either case of checking info, we employ the conditional operator.

Here's the definition of Greeting:

function Greeting({ name, info }) {
   return (
      <header>
         <h1>Hello {name}!</h1>
<p>{info ? info.text : 'This is the default info.'}</p> </header> ); }

Let's now test it.

First, without info:

function App() {
   return (
      <Greeting name="Dennis" />
   );
}

Live Example

And now with it:

function App() {
   return (
      <Greeting name="Dennis" info={{ text: 'Using an object this time.' }} />
   );
}

Live Example

And it works flawlessly!

As we shall explore later on in this course, using the conditional operator is really common in React apps when we ought to indicate loading while some data related to the underlying component is fetched over the network.

When the data is in the process of loading, a loading indicator is shown, but when the data does load completely, some result utilizing that data is rendered.

Conditionally removing attributes

Before we conclude this chapter, it's worthwhile discussing an important point related to conditionally controlling the presence of a given attribute on an element in React.

That is, when an attribute on a React element representing a DOM element is set to null or undefined, that attribute is effectively removed from the underlying DOM element node.

For example, suppose we have the following code, with the className attribute:

<div className="text-blue">Hello</div>

If we inspect the underlying DOM element node in the browser for this React element, we see that it indeed has a class attribute set on it, with the value "text-blue":

The <div> element inspected in the browser.
The <div> element inspected in the browser.

But now let's set the className attribute to null:

<div className={null}>Hello</div>

Here's the same element node inspected again:

The <div> element inspected in the browser.
The <div> element inspected in the browser.

See, the attribute has been removed from the element, all thanks to setting it to null in the JSX.

Keep in mind that setting the className attribute to true or false would produce the same effect:

<div className={false}>Hello</div>
The <div> element inspected in the browser.
The <div> element inspected in the browser.

However, don't get deceived by this behavior of className; it does NOT apply to every attribute. In particular, it doesn't work for Boolean HTML attributes, such as contentEditable (remember this is JSX).

In the following code, we set contentEditable to false but obviously, as per our expectation, this doesn't remove the attribute but rather sets it to "false":

<div contentEditable={false}>Hello</div>
The <div> element inspected in the browser.
The <div> element inspected in the browser.

In HTML, the contenteditable attribute is a Boolean attribute and so it makes perfect sense for React to follow this approach.

But then how to remove contenteditable from the HTML if we wish to?

Well, in React the behavior of null (and undefined) for an attribute's value is the same across all attributes. That is, null always leads to an attribute being removed.

So we just need to set contentEditable to null:

<div contentEditable={null}>Hello</div>
The <div> element inspected in the browser.
The <div> element inspected in the browser.

Henceforth, for consistency, we'll always set an attribute to null if we wish to remove it (even if setting it to false would have the same effect) in this course. And we recommend you to follow along.

Consistency is key in programming.