7 Ways to Implement Conditional Rendering in React Applications

Introduction

With React, we can build Single Page Applications that are dynamic and highly interactive. One way we fully utilize such interactivity is through conditional rendering.

Conditional rendering as a term describes the ability to render different UI markup based on certain conditions. In React-speak, it is a way to render different elements or components based on a condition. This concept is applied often in the following scenarios:

  • Rendering external data from an API
  • Showing/hiding elements
  • Toggling application functionality
  • Implementing permission levels
  • Authentication and Authorization

In this article, we examine seven(7) ways to implement such conditional rendering in React applications.

The Challenge

As a challenge, based on the value of isLoggedIn in our component state, we want to be able to display a Login button if the user isn’t logged in, and a Logout button if he/she is.

This is what our starter component looks like:

Visually:

Code:

import React, { Component } from "react";
import ReactDOM from "react-dom";
import "./styles.css";


class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      isLoggedIn: true
    };
  }
  render() {
    return (
      <div className="App">
        <h1>
          This is a Demo showing several ways to implement Conditional Rendering
          in React.
        </h1>
        <button>Login</button>
        <button>Logout</button>
      </div>
    );
  }
}


const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

Bear in mind that within the code snippets implies that some code which isn’t directly connected with the point being explained goes there.

1. Using an If…else Statement

An if…else statement allows us to specify that a particular action be carried out if a condition evaluates to true as well as do something else if it doesn’t. Using the sample project, we will examine two ways if…else conditions may be used to implement conditional rendering in React.

Extracting the conditional rendering into a function

In JSX, we are able to mix up JavaScript code with our markup to ensure stunning interactivity within our application. To do this we use a set of curly braces {} and write our JavaScript within. The caveat however is that there is a limit to what can be done within such braces. As a result the code snippet below would fail to achieve the desired result.

// index.js
...
render() {
    let {isLoggedIn} = this.state;
    return (
      <div className="App">
        <h1>
          This is a Demo showing several ways to implement Conditional Rendering
          in React.
        </h1>
        {
          if(isLoggedIn){
            return <button>Logout</button>
          } else{
            return <button>Login</button>
          }
        }
      </div>
    );
}
...

To understand more about this behavior, visit this link.

To solve this, we extract the conditional logic into a function as shown below:

// index.js
...
render() {
    let {isLoggedIn} = this.state;
    const renderAuthButton = ()=>{
      if(isLoggedIn){
        return <button>Logout</button>
      } else{
        return <button>Login</button>
      }
    }
    return (
      <div className="App">
        <h1>
          This is a Demo showing several ways to implement Conditional Rendering
          in React.
        </h1>
        {renderAuthButton()}
      </div>
    );
  }
...

Notice that we extract the logic from JSX into a function renderAuthButton. Thus, we only need to execute the function within the JSX curly braces.

Multiple return statements

In using this method, the component must be kept as simple as possible to avoid a wasted re-render of sibling or parent components. As a result of this, we create a new functional component called AuthButton.

// AuthButton.js

import React from "react";

const AuthButton = props => {
  let { isLoggedIn } = props;
  if (isLoggedIn) {
    return <button>Logout</button>;
  } else {
    return <button>Login</button>;
  }
};
export default AuthButton;

AuthButton returns various elements/components depending on the value of state that is passed down via the isLoggedIn props. Thus we import it in our index.js and pass down the appropriate state as shown below:

// index.js
...
import AuthButton from "./AuthButton";

...
  render() {
    let { isLoggedIn } = this.state;
    return (
      <div className="App">
      ...
        <AuthButton isLoggedIn={isLoggedIn} />
      </div>
    );
  }
...

You must avoid doing this:

// index.js
...
render() {
    let { isLoggedIn } = this.state;
    if (isLoggedIn) {
      return (
        <div className="App">
          <h1>
            This is a Demo showing several ways to implement Conditional
            Rendering in React.
          </h1>
          <button>Logout</button>;
        </div>
      );
    } else {
      return (
        <div className="App">
          <h1>
            This is a Demo showing several ways to implement Conditional
            Rendering in React.
          </h1>
          <button>Login</button>
        </div>
      );
    }
  }
}
...

The snippet above would achieve the same result but bloat the component unnecessarily while introducing performance issues as a result of constantly re-rendering an unchanging component.

2. Using Element Variables

Element variables are an extension of **Extracting the conditional rendering into a function** as shown above. Element variables are simply variables that hold JSX elements. Thus we can conditionally assign elements/ components to these variables outside our JSX and only render the variable within JSX. See demo below:

// index.js
...
render() {
    let { isLoggedIn } = this.state;
    let AuthButton;
    if (isLoggedIn) {
      AuthButton = <button>Logout</button>;
    } else {
      AuthButton = <button>Login</button>;
    }
    return (
      <div className="App">
        <h1>
          This is a Demo showing several ways to implement Conditional Rendering
          in React.
        </h1>
        {AuthButton}
      </div>
    );
  }
...

Notice how we conditionally assign values(components) to AuthButton and then we only have to render it neatly within our JSX.

3. Using a Switch Statement

As shown previously, we can conditionally return different markup from a component based on set conditions using an if…else statement. The same could be achieved with a switch statement where we can specify the markup for various conditions. See example below:

// AuthButton.js
import React from "react";

const AuthButton = props => {
  let { isLoggedIn } = props;
  switch (isLoggedIn) {
    case true:
      return <button>Logout</button>;
      break;
    case false:
      return <button>Login</button>;
      break;
    default:
      return null;
  }
};
export default AuthButton;

Notice how we return various buttons based on the value of isLoggedIn. It is more reasonable to apply this method when there’s more than two possible values or outcomes. You may also do away with the break statement as the return statement automatically terminates the execution.

Note: Returning **null** from a component will cause it to hide itself/display nothing. This a good way to toggle visibility of components.

4. Ternary Operators

The conditional (ternary) operator is the only JavaScript operator that takes three operands. This operator is frequently used as a shortcut for the if statement.

If you are familiar with ternary operators, then you are aware that is is simply a more concise way to write an if statement. Thus we have:

// index.js
...
render() {
    let { isLoggedIn } = this.state;
    return (
      <div className="App">
        <h1>
          This is a Demo showing several ways to implement Conditional Rendering
          in React.
        </h1>
        {isLoggedIn ? <button>Logout</button> : <button>Login</button>}
      </div>
    );
  }
...

In cases where, this approach makes the component bloated, bulky or less readable, you may encapsualte the conditional within a functional component as shown below:

// AuthButton.js
import React from "react";

const AuthButton = props => {
  let { isLoggedIn } = props;
  return isLoggedIn ? <button>Logout</button> : <button>Login</button>;
};

export default AuthButton;

5. Logical && (Short Circuit Evaluation with &&)

Short circuit evaluation is a technique used to ensure that there are no side effects during the evaluation of eperands in an expression. The logical && helps us specify that an action should be taken only on one condition, otherwise, it would be ignored entirely. This is useful for situations where you only need to take an action when a certain condition is true, otherwise do nothing.

For instance if we only needed to show the Logout button if the person is logged in, otherwise we do nothing. We’d have something like this:

// index.js
...
render() {
    let { isLoggedIn } = this.state;
    return (
      <div className="App">
        <h1>
          This is a Demo showing several ways to implement Conditional Rendering
          in React.
        </h1>
        {isLoggedIn && <button>Logout</button>}
      </div>
    );
  }
...

This would display the logout button if isLoggedIn is true otherwise it’d display nothing. We could adapt this to fit our use case as shown below. However, it is not advisable.

// index.js
...
return (
      <div className="App">
        <h1>
          This is a Demo showing several ways to implement Conditional Rendering
          in React.
        </h1>
        {isLoggedIn && <button>Logout</button>}
        {!isLoggedIn && <button>Login</button>}
      </div>
    );
  }
...

This would render the right button based on the value of isLoggedIn. However, this isn’t recommended as there are better, cleaner ways to achieve the same effect. Also this could easily make your code look messy and unintuitive once the component gets slightly larger.

6. Using Immediately Invoked Function Expressions(IIFEs)

Earlier we covered that JSX limitations make it unable to execute every type of JavaScript code. This isn’t entirely true as there are ways to bypass such behavior. One such way is by using IIFEs.

An IIFE (Immediately Invoked Function Expression) is a JavaScript function that runs as soon as it is defined. It’s used in the format below.

(function () {
    statements
})();

You may learn more about IIFE’s from MDN here.

With this technique, we are able to to write conditional logic directly within JSX but wrapped within an anonymous function that is immediately invoked on evaluation of that portion of our code. See example below:

//index.js
...
render() {
    let { isLoggedIn } = this.state;
    return (
      <div className="App">
        <h1>
          This is a Demo showing several ways to implement Conditional Rendering
          in React.
        </h1>
        {(function() {
          if (isLoggedIn) {
            return <button>Logout</button>;
          } else {
            return <button>Login</button>;
          }
        })()}
      </div>
    );
  }
...

This can also be written in a slightly more concise manner using an arrow function as shown below:

// index.js
...
return (
      <div className="App">
        <h1>
          This is a Demo showing several ways to implement Conditional Rendering
          in React.
        </h1>
        {(()=> {
          if (isLoggedIn) {
            return <button>Logout</button>;
          } else {
            return <button>Login</button>;
          }
        })()}
      </div>
    );
  }
...

7. Using Enhanced JSX

Certain libaries expose functionality to extend JSX, thus making it possible to implement conditional rendering directly with JSX. One of such libraries is JSX Control Statements. It is a Babel plugin that transforms component-like control statements into their JavaScript counterparts during transpilation. See example below for how this may be implemented.

// index.js
...
return (
      <div className="App">
        <h1>
          This is a Demo showing several ways to implement Conditional Rendering
          in React.
        </h1>
        <Choose>
          <When condition={isLoggedIn}>
             <button>Logout</button>;
          </When>
          <When condition={!isLoggedIn}>
             <button>Login</button>;
          </When>
        </Choose>
      </div>
    );
  }
...

This approach is however not recommended as the code you write is eventually transpiled to a regular JavaScript conditional. It is probably always better to just write JavaScript than add an extra dependency over something so trivial.

Performance Concerns

As a general rule, it is best to ensure that in implemementing conditional rendering you:

  • Do not change the position of components arbitrarily in order to prevent components from unmounting and remounting unnecessarily.
  • Change only the markup that is concerned with the conditional rendering and leave out every other unchanging bit of the component.
  • Do not bloat your component unnecessarily within the render method, thus causing components to delay in rendering.

For more on writing high performing conditionals in React, see this article by Cole Williams.

Conclusion

We have successfully examined 7 ways to implement conditional rendering in React. Each method has it’s own advantage and the choice of which to use is mostly dependent on the use case. Things to consider include:

  • The size of markup to be rendered conditionally
  • The number of possible outcomes
  • Which would be more intuitive and readable

Generally, keep in mind the following recommendations:

  • When there is only one expected outcome, the Logical && Operator comes in very handy.
  • For boolean situations or use cases with only 2 possible outcomes, you may use If…else, Element variables, Ternary Operators and IIFEs.
  • For cases of more than 2 outcomes, you may use a Switch statement, an extracted function or extracted functional component.

This is however merely a recommendation and the choice of which to go with is primarily yours.

Further Reading

You may learn more via the following resources:

Originally posted on DigitalOcean Community Tutorials
Author: Philip Obosi

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *