Short-circuit Evaluation in React

web developer, developer, freelance, react, redux, node, javascript, css, html, ruby, rails, postgresql, mongodb, gatsby, graphql, gql, software engineer
Photo by Matheus Cenali via Unsplash

When you're new to React, or JavaScript in general, you'll commonly see this syntax out in the wild and in tutorials:

function MyComponent(props) {
  const { headerCopy } = props;
  return <div>{headerCopy && <h1>{headerCopy}</h1>}</div>;
}

That weird syntax on the fifth line is known as short-circuit evaluation. This pattern can be used to conditionally render components in React, however, there's a few gotchas.

What do you think this piece of code will render if headerCopy is equal to "My Header"? (Remember: non-empty strings are considered truth-y!). Will the "My Header" be rendered inside of the emphasis tags?

function MyComponent(props) {
  const { headerCopy } = props;
  return <div>{headerCopy && <em>{headerCopy}</em>}</div>;
}

The answer here is no! Why? Since "My Header" is a truth-y value and not one of the ones React specifically ignores, you'll run into the "short-circuit" effect of this pattern– My Header will be rendered as plain-text without the em tags.

But, how do I use this properly?

It's pretty simple–you just have to remember a few rules. React will render anything that is not typeof, undefined, or a Boolean. So, in this instance, you have a few options.

Cast as a Boolean

Since Boolean is one of the types that React knows not the render, we can explicitly cast our value as a Boolean :

function MyComponent(props) {
  const { headerCopy } = props;
  return <div>{Boolean(headerCopy) && <em>{headerCopy}</em>}</div>;
}

This won't be short-circuited as Boolean(headerCopy) will still evaluate to true but React knows not to render it.

The Bang-Bang / Not Not / Double Bang Operator (!!)

If you've never seen that before, it's basically a shorter way to cast as a Boolean. If you're familiar with logical operators, you know that prefixing a value with a Bang (!) operator reverses the value of it. The only way to do this is to cast it as a Boolean, so JavaScript does that for you. The SECOND Bang flips it back to it's original truth-y/false-y value while keeping it casted as a Boolean. Confused? That's normal! Let's look at some examples:

!true; // Evaluates to false
!false; // Evaluates to true
!'Hello'; // Evaluates to false
!''; // Evaluates to true

// The DOUBLE BANG!
!!true; // Evaluates to true!
!!false; // Evaluates to false!
!!'Hello'; // Evaluates to true!
!!''; // Evaluates to false!

With those examples in mind, what do you think !!0 would evaluate to? If you guessed false, you're right! Since 0 is false-y, and we're casting it, reversing it, and then flipping it back, it evaluates to it's associated Boolean value. So, how do we use that as a replacement to fix our short-circuit evaluations? Like this:

function MyComponent(props) {
  const { headerCopy } = props;
  return <div>{!!headerCopy && <em>{headerCopy}</em>}</div>;
}

Boom! No worries about the actual type of the prop you're using on the left-side of the evaluation. Things will work as expected.

Ternary Conditionals

The last option for in-line conditional rendering involves doing a full ternary conditional. These are my preference as I often have a false state that I want to render for in the condition.

function MyComponent(props) {
  const { headerCopy } = props;
  return (
    <div>
      {headerCopy ? <em>{headerCopy}</em> : <strong>N/A</strong>}
    </div>
  );
}

If you don't want to render anything in one of the conditions, simply pass null and React will ignore it:

function MyComponent(props) {
  const { headerCopy } = props;
  return <div>{headerCopy ? <em>{headerCopy}</em> : null}</div>;
}

Summary

In addition to these three methods, you can also things like bringing your component logic outside of the render and prepare it beforehand. It all depends on your preference though an argument could be made for readability of the above three options versus long-winded if/else blocks to determine which component to render. But, that's a topic for another post! πŸ‘‹πŸ»

Tags:


Next: A Fresh Coat of Paint