ReactT2 Dark_1200x303

Without if statements in JSX, how do you control your application's flow? Let's explore how to render or NOT render elements in React.

You can't embed if statements in JSX. So how do you control what is displayed? Controlling flow through your application is fundamental to programming, and it's no different in React. In this article, we are going to answer the question: How do I show or hide something in React?

I started to brainstorm the different ways to show and hide things in React, and it turns out there are more ways than you might think! We'll cover some of the pros and cons to each approach, and how you can test for the presence of an element with React Testing Library.

Full source code can be found here.

Returning Null

In modern React, a component is little more than a function whose job it is to return the value that is to be rendered. Just like regular functions, functional components can have multiple return values. If what the component renders is an "all or nothing" situation, the simplest way to control whether an element is rendered is to avoid returning any JSX at all, and return null instead.

Because this if statement is not embedded inside of JSX but is just part of the regular JavaScript portion of the function, you are free to use any sort of JS construct that you like. In this example, if the product is not available, we're just going to return null.

const AddToCart = ({ available }) => {
  if (!available) return null;

  return (
    <div className="full tr">
      <button className="product--cart-button">Add to Cart</button>
    </div>
  );
};

Ternary Display

When you need to control whether one element vs. another is displayed, or even one element vs. nothing at all (null), you can use the ternary operator embedded inside of a larger portion of JSX.

In this case, if there are no products remaining, we will display "Sold Out"; otherwise we will display the number of products remaining.

<div className="half">
  <p>{description}</p>

  {remaining === 0 ? (
    <span className="product-sold-out">Sold Out</span>
  ) : (
    <span className="product-remaining">{remaining} remaining</span>
  )}
</div>

Shortcut Display

If you want to only display something if a value is true and there is nothing to display if the result is false, there is a shortcut rather than having null on the falsey side of a ternary operator. It involves using a conditional inside of your JSX that looks like checkIfTrue && <span>display if true</span>. Because if statements that use && operands stop as soon as they find the first value that evaluates to false, it won't reach the right side (the JSX) if the left side of the equation evaluates to false.

Let's see this in action! We will only display the rest of the product name if it has something to display:

<h2>
  <span className="product--title__large">{nameFirst}</span>
  {nameRest.length > 0 && (
    <span className="product--title__small">{nameRest.join(" ")}</span>
  )}
</h2>

I have to point out that this causes problems in React Native, where it doesn't know to handle false during output, and ends up causing an error. In React Native you should use a ternary operator with null being returned on the false side:

<h2>
  <span className="product--title__large">{nameFirst}</span>
  {nameRest.length > 0 ? (
    <span className="product--title__small">{nameRest.join(" ")}</span>
  ) : null}
</h2>

Using Style Property

Up until this point we have chosen between rendering an element or not. What if we wanted to render an element but not have it seen? At this point we have a few options to focus on — the first being directly modifying the HTML element's style property, setting CSS attributes such as display and opacity. In this short example below we will set the display property to be either block or none depending on the value contained within showInfo. Once again, a ternary operator is used inside embedded JSX to control the flow of our application.

<div style={{ display: showInfo ? "block" : "none" }}>info</div>

Modifying CSS Classes

Along the same theme as modifying style attributes, we can modify which class an element has, giving us the ability to control an element's display, opacity, or even hiding it off the side of the screen as might be done with a hamburger menu when it is in its closed state.

In the example below, the nav element is off the left side of the screen with left: -200px, but when the class open is added to the nav element, it transitions to having left: 0px, and suddenly it is visible again.

nav {
  position: fixed;
  left: -200px;
  width: 200px;
  padding: 1rem;
  transition: 0.3s all ease;
  z-index: 1000;
  height: 100vh;
  background: #cfd8dc;
}

nav.open {
  left: 0px;
}

We can toggle this CSS class using state that is toggled within the onClick of a button (the hamburger), choosing to add a class or not with a ternary condition className={open ? "open" : null}.

const Nav = () => {
  const [open, setOpen] = React.useState(false);

  return (
    <nav className={open ? "open" : null}>
      <button
        onClick={() => {
          setOpen(!open);
        }}
      >
        hamburger
      </button>
      <ul>{/* elements */}</ul>
    </nav>
  );
};

Visibility Animation with react-spring

Rather than manipulating classes and style attributes ourselves, we can reach for a third-party library to do it for us. In this case we are using react-spring, which can toggle any numerical CSS attribute using physics-based properties such as the mass, tension, and friction. If those aren't completely obvious to you (as is definitely my case!), there is a neat react-spring visualizer available to help you get the settings right.

import { useSpring, animated } from "react-spring";

const SpringIn = ({ children }) => {
  const props = useSpring({
    opacity: 1,
    from: { opacity: 0 },
    config: { mass: 10, tension: 10, friction: 10 }
  });
  return <animated.div style={props}>{children}</animated.div>;
};

With our custom component SpringIn, simply wrapping <SpringIn><div>any content</div></SpringIn>, we are able to have that element fade in using react-spring.

Testing Existence with React Testing Library

Testing should be an important part of your React development process, and using React Testing Library we can test for the presence or lack of presence of an element being rendered.

The first example uses getByText to find the element, and we expect it toBeInTheDocument, whereas the second example uses queryByText to verify it toBeNull. We switched from getByText to queryByText because getByText will raise an error if it can't find the element that you are looking for, but in the second example, that's exactly what we expect to find!

import React from "react";
import { render, fireEvent } from "@testing-library/react";
import { AddToCart, Nav } from "./App";

test("renders cart button when available", () => {
  const { getByText } = render(<AddToCart available={true} />);

  expect(getByText(/cart/i)).toBeInTheDocument();
});

test("hides cart button when not available", () => {
  const { queryByText } = render(<AddToCart available={false} />);

  expect(queryByText(/cart/i)).toBeNull();
});

Testing for Classes with React Testing Library

We can also use React Testing Library to check if an element has a certain CSS class or not. In the example below, our nav is originally hidden, which means that it doesn't have the open class, but after toggling state by clicking on the hamburger menu, we can verify that it correctly has the open class.

test("adds class to nav when toggled", () => {
  const { getByTestId } = render(<Nav />);
  const navElement = getByTestId("nav");

  expect(navElement).not.toHaveClass("open");
  fireEvent.click(getByTestId("hamburger"));
  expect(navElement).toHaveClass("open");
});

Conclusion

In this article we covered six different ways to show or not show an element in React. Sometimes we chose to not have it rendered at all, using a few different types of conditional statements, but we also looked at how to have the element rendered, but to not have it visible to the user, playing with style attributes and CSS classes. Lastly we used React Testing Library to verify that a certain element was correctly rendered, or not rendered.


leigh-halliday
About the Author

Leigh Halliday

Leigh Halliday is a full-stack developer specializing in React and Ruby on Rails. He works for FlipGive, writes on his blog, and regularly posts coding tutorials on YouTube.

Related Posts

Comments

Comments are disabled in preview mode.