17Jan
Conditional Rendering Methods in React
Conditional Rendering Methods in React

While conditionals are common and useful when building web applications, it can be tricky trying to implement such in a React component. JSX makes it possible to reuse the conditionals you are already familiar with when working with JavaScript, as such, you need not learn a new one. In this tutorial, we’re going to be looking at some of the best approaches to handling conditionals when working with React. Most of the code we’ll try out will make use of a login and logout logic – the component will either render the view for logging in or logging out depending on a particular condition. This is similar to how your favorite social media platform works, you’ll only see the login page when you are logged out.

When using a conditional in a component, the component has to determine what to render based on a defined condition. This is similar to how conditionals work in all programming languages.

If/else

This is the most popular way to handle conditionals in JavaScript and React. It is possible that it is the first that comes to mind when there’s a need to make use of conditionals. In this case, we will make use of the if/else statement to conditionally render a login or logout view. Let’s start with setting up the constructor part of our component

class App extends React.Component {
  state = {
    username: "",
    input: "",
    isLoggedIn: false
  }
}

We will be making use of isLoggedIn to determine what gets rendered to the user. Such that when the value is true, (which means a user is logged in), we’ll display the option to logout. For us to do that we’ll make use of a method that gets called so that the state of the application can change.

handleInput = (e) => {
    this.setState({ input: e.target.value })
  }
  
  handleLogin = () => {
    this.setState({
      isLoggedIn: true,
      username: this.state.input
    })
  }
  
  handleLogout = () => {
    this.setState({
      isLoggedIn: false,
      username: ""
    })
  }

handleInput() will be called when the value of the input field changes. The input field will be used to collect the username of the person who wants to log in. For the purpose of this tutorial, we will not have any form of validation for the field. On hitting the submit button after the username has been entered, we make use of handleLogin() to set the username and change the value of isLoggedIn from false to true. handleLogout() does the opposite of that – it clears the username and set isLoggedIn to false.

With that, the render() method will look like this.

render() {
    const { username, isLoggedIn } = this.state
    if (isLoggedIn === false) {
      return (
        <div className="box">
          <form onSubmit={this.handleLogin}>
            <h1>Login Here!</h1>
            <div className="field">
              <label
                className="label"
                htmlFor="username">
                Username:
              </label>
              <div className="control">
                <input
                  type="text"
                  name="username"
                  onChange={this.handleInput}
                  className="input"
                />
              </div>
            </div>
            <div className="field">
              <button className="button is-light" type="submit">Submit</button>
            </div>
          </form>
        </div>
      )
    } else {
      return (
        <React.Fragment>
          <div className="box">
            <p>Hello {username}!</p>
            <p>Welcome onboard!</p>
            <div className="field">
              <button
                className="button"
                onClick={this.handleLogout}
              >
                Logout
              </button>
            </div>
          </div>
        </React.Fragment>
      )
    }
  }

You can see that we make use of the if/else statement to determine which gets rendered. What gets rendered is dependent on the value of isLoggedIn. Since the code is not too much, we can easily have them all in a single render() method. Else, to make things cleaner, we’d have opted to have separate components for the logging in and out. Here is a demo pen you can check out to see how the above example works.

Ternary Operator

This is my favorite because it makes the code look cleaner and concise, compared to using an if/else statement. The ternary operator is wrapped in curly braces and begins with the condition, which is then followed by a question mark. After that, you have what you want to render when the condition is met, next is a colon and what should be rendered when the condition is not met.

{
  user === "Kingsley" ? (
    <RenderKingsleyComponent />
  ) : (
    <RenderAnotherComponent />
  )
}

The condition is met when the value of user is Kingsley, this will cause <RenderKingsleyComponent /> to be evaluated, else <RenderAnotherComponent /> will be. Similar to what we have above, we can make use of the ternary operator in the place of the if/else statement like so.

render() {
    const { username, isLoggedIn } = this.state;
    return (
      <React.Fragment>
        {!isLoggedIn ? (
          <div className="box">
            <form onSubmit={this.handleLogin}>
              <h1>Login Here!</h1>
              <div className="field">
                <label className="label" htmlFor="username">
                  Username:
                </label>
                <div className="control">
                  <input
                    type="text"
                    name="username"
                    onChange={this.handleInput}
                    className="input"
                  />
                </div>
              </div>
              <div className="field">
                <button className="button is-light" type="submit">
                  Submit
                </button>
              </div>
            </form>
          </div>
        ) : (
          <div className="box">
            <p>Hello {username}!</p>
            <p>Welcome onboard!</p>
            <div className="field">
              <button className="button" onClick={this.handleLogout}>
                Logout
              </button>
            </div>
          </div>
        )}
      </React.Fragment>
    );
  }

The option to log in will be rendered when isLoggedIn is false, else what will be shown will be the username entered and a button to log out. You can check out this pen to see the example above.

Returning null

You might be thinking, what about cases where you want to evaluate a condition and render one thing if the condition is met. For such a scenario, you can choose to return null when the condition is not met. In a typical example, let’s say you want to render a button when a value evaluates to true, you can make use of what we have in this pen.

class App extends React.Component {
  state = {
    showButton: true
  };

  render() {
    const { showButton } = this.state;
    { if (showButton) {
      return (
        <button className="button is-light" type="submit">
        Click Here!
      </button>
      )
    } else {
      return null
    }}
  }
}

The component will only render the button when showButton is true, nothing gets rendered if the value of showButton is false. You can also make use of what is called the logical && (AND) operator.

Logical && Operator

The issue with the above example is that we are handling scenarios where the condition is false, even though we won’t be rendering anything to the user. Using the logical && operator, we can do away with that part. So the above example will look like this.

class App extends React.Component {
  state = {
    showButton: true
  };

  render() {
    const { showButton } = this.state;
    return (
      <div>
        { showButton && (
          <button className="button is-light" type="submit">
            Click Here!
          </button>
        )}
      </div>
    );
  }
}

You can check Codepen for a demo. This looks cleaner. We can take it further by adding a button to toggle the value of showButton, such that the submit button gets shown or hidden, as I did in this pen.

class App extends React.Component {
  state = {
    showButton: true
  };

  toggleButton = () => {
    this.setState({
      showButton: !this.state.showButton
    });
  };

  render() {
    const { showButton } = this.state;
    return (
      <React.Fragment>
        <div className="box">
          <button
            onClick={this.toggleButton}
            className="button is-dark">
            Toggle Login Button
          </button>
        </div>
        { showButton && (
          <div className="box">
            <button
              className="button is-light"
              type="submit">
            Login Here!
          </button>
          </div>
        )}
      </React.Fragment>
    );
  }
}

Switch Case

Switch case statement comes in handy when you have to handy multiple conditions. In React, switch cases are popularly used when making with Redux, in this tutorial we will see how to make use of switch cases for conditional rendering. Using the login and logout examples we have been using, we will separate these parts into their own components. Here is a pen that shows what we are working on.

The Login component will look like this

class Login extends React.Component {
  state = {
    input: "",
    username: ""
  };

  handleInput = e => {
    this.setState({ input: e.target.value });
  };

  handleSubmit = () => {
    const { handleLogin } = this.props;
    handleLogin(this.state.input);
  };

  render() {
    return (
      <div className="box">
        <form onSubmit={this.handleSubmit}>
          <h1>Login Here!</h1>
          <div className="field">
            <label className="label" htmlFor="username">
              Username:
            </label>
            <div className="control">
              <input
                type="text"
                name="username"
                onChange={this.handleInput}
                className="input"
              />
            </div>
          </div>
          <div className="field">
            <button className="button is-light" type="submit">
              Submit
            </button>
          </div>
        </form>
      </div>
    );
  }
}

This component will collect the username and send it to the parent component using this.handleLogin(). The username will be used in the Logout component, the parent component passes it as props to the Logout component where it is displayed, with the option to also log out by clicking a button.

const Logout = props => {
  return (
    <div className="box">
      <p>Hello {props.username}!</p>
      <p>Welcome onboard!</p>
      <div className="field">
        <button className="button" onClick={props.handleLogout}>
          Logout
        </button>
      </div>
    </div>
  );
};

Now we can have the App component to look like this.

class App extends React.Component {
  state = {
    username: "",
    isLoggedIn: false
  };

  handleLogin = value => {
    this.setState({
      isLoggedIn: true,
      username: value
    });
  };

  handleLogout = () => {
    this.setState({
      isLoggedIn: false,
      username: ""
    });
  };

  render() {
    const { username, isLoggedIn } = this.state;
    switch (isLoggedIn) {
      case false:
        return <Login handleLogin={this.handleLogin} />;
      case true:
        return <Logout handleLogout={this.handleLogout} username={username} />;
      default:
        return null;
    }
  }
}

This is similar to how we used the if/else statement, in both cases we’re making use of isLoggedIn to determine what gets displayed.

Higher-Order Components

Higher-Order components are useful for cases where you want to reuse a certain logic across multiple components. With that, it is possible to include a conditional rendering inside the higher-order component, such that the component that is returned is dependent on the result of the condition. As we have in this pen, we are going to create a high-order component that handles cases of either returning the Login or Logout component. While reusing the Login and Logout component of the previous example, the higher-order component will look like this.

const withGuest = WrappedComponent => ({ isLoggedIn, ...props }) => {
  if (isLoggedIn) {
    return <WrappedComponent {...props} />;
  }

  return <Login handleLogin={props.handleLogin} />;
};

The component passed to the withGuest component will be returned if is isLoggedIn evaluates to true, else the Login component will be returned.

const Main = withGuest(Logout);

class App extends React.Component {
  state = {
    username: "",
    isLoggedIn: false
  };

  handleLogin = value => {
    this.setState({
      isLoggedIn: true,
      username: value
    });
  };

  handleLogout = () => {
    this.setState({
      isLoggedIn: false,
      username: ""
    });
  };

  render() {
    const { username, isLoggedIn } = this.state;

    return (
      <Main
        isLoggedIn={isLoggedIn}
        username={username}
        handleLogin={this.handleLogin}
        handleLogout={this.handleLogout}
      />
    );
  }
}

Here are creating a new component called Main and we pass the Logout component to the higher-order component. The Main component received the needed prop to determine the value of isLoggedIn, and also to log the user in or out.

Enum

We can make use of JavaScript to create a conditional rendering in our React application. First, you need to know that you create an enum like this;

const Size = {
  SMALL: 1,
  MEDIUM: 2,
  LARGE: 3,
};

In this tutorial, we will have the function that returns a component based on the value passed to it – the value matches the key of the component, the component is then returned.

const getUserComponent = value => {
  return {
    loggedOut: (
      <Login
        handleLogin={value.handleLogin}
      />
    ),
    loggedIn: (
      <Logout
        username={value.username}
        handleLogout={value.handleLogout}
      />
    )
  };
};

We can then make use of the above function in a component.

const UserState = ({ status, ...props }) => {
  return (
    <React.Fragment>
      {getUserComponent(props)[status]}
    </React.Fragment>
  )
};

This component will be included in our App component, it receives props from the parent (App) component, which it then uses the call the getUserComponent() function. In return, we either get the Login or Logout component. Here is how the App component looks like.

class App extends React.Component {
  state = {
    username: "",
    status: "loggedOut"
  };

  handleLogin = value => {
    this.setState({
      username: value,
      status: "loggedIn"
    });
  };

  handleLogout = () => {
    this.setState({
      username: "",
      status: "loggedOut"
    });
  };

  render() {
    const { username, status } = this.state;

    return (
      <UserState
        status={status}
        username={username}
        handleLogin={this.handleLogin}
        handleLogout={this.handleLogout}
      />
    );
  }
}

We reused the Login and Logout component of previous examples, you can check out this pen.

Conclusion

The conditional rendering method you use in your application should be dependent on the complexity of the condition. For example, you won’t want to have if/else statements littered all over your component. You can make use of the logical && condition when you only need to render one thing based on the result of the condition. I find myself using the ternary condition over the if/else statement.

3 Replies to “Conditional Rendering Methods in React”

  1. Hi, Kingsley, why you didn’t mention: Immediately invoked function expressions (IIFEs) and Subcomponents?

    1. Kingsley Silas 5 years ago

      Hello Nikita,
      I don’t think IIFEs are a good option, you can achieve what you want with any of the options mentioned in the piece. Subcomponents can be used by breaking the logic into their own components and using the ternary operators. Basically, it’s the use of “ternary operators” which was covered in the piece, the difference is that you use break the parts to be rendered into their own components. In this case, that means you’ll have to separate the login and logout feature into their own components like I did in the switch case example.

      1. I see. Thanks for the explanation, really appreciate it!

Leave a Reply