Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

React JSX: How to Do It the Right Way, Part II

DZone's Guide to

React JSX: How to Do It the Right Way, Part II

In this article, we'll learn how to write conditional statements, using if-else and switch syntaxes, when rendering components.

· Web Dev Zone ·
Free Resource

Deploy code to production now. Release to users when ready. Learn how to separate code deployment from user-facing feature releases with LaunchDarkly.

In the previous part of React JSX series, we took a look at how to correctly loop through arrays and objects in React. In this article, we'll help you learn how to write conditional statements when rendering components.

Everything below applies to React Native as well!

Conditional Statements Inside React Render

While learning to code in React, most of us have probably tried this and realized it won't work:

render() {
    return (
        <div>
            {
                // this won't work
            }
            {
                if (condition) {
                    // do something
                } else {
                    // do something else
                }
            }
        </div>
    )
}

JSX is just a syntactic sugar for function calls and object construction, and, although JavaScript is pretty flexible, we still can't pass the code like the if-else above as a parameter to a function.

Below are the correct ways to do the conditioning!

Let's say we have a flight object and in our Flight component, we want to show whether it's canceled or not. The most usual way to do simple conditioning like this is via ternary expressions:

render() {
    return (
        <p>
            {
                flight.cancelled ?
                    'Cancelled'
                    :
                    'Regular'
            }
        </p>
    )
}

Ternary expressions are okay for simpler stuff but what happens if we have something more complex?

Let's say, what if we have a situation where we should use an else if statement?

We can nest these expressions, of course (if we can have nesting in SASS/LESS, why do you think we couldn't have ternary expressions nested?):

render() {
    return (
        <p>
            {
                flight.cancelled ?
                    'Cancelled'
                    :
                    ( 
                       flight.arrived ?
                           'Arrived'
                           :
                           'Regular'
                    )
            }
        </p>
    )
}

However, as with every nesting, this shouldn't be overused, as it can easily pile up and start looking pretty messy and unreadable. What's the better way then? Do the conditioning above the return statement:

render() {
    let status;
    if (flight.cancelled) {
        status = 'Cancelled';
    } else if (flight.arrived) {
        status = 'Arrived';
    } else {
        status = 'Regular';
    }
    return (
        <p>
            { status }
        </p>
    )
}

Now, in previous examples, we were only rendering a status in our component, but usually, there will be much more to render. So, if we want to render the departure time, the destination, the arrival time, and status, for example, it might look something like this:

render() {
    let status;
    if (flight.cancelled) {
        status = 'Cancelled';
    } else if (flight.arrived) {
        status = 'Arrived';
    } else {
        status = 'Regular';
    }
    return (
        <div>
            <p>
                Destination: { flight.destination }
            </p>
            <p>
                Departure time: { flight.departureTime }
            </p>
            <p>
                Arrival time: { flight.arrivalTime }
            </p>
            <p>
                Flight status: { status }
            </p>
        </div>
    )
}

Now, this is okay, it's working, but we're polluting the render method of a component. Imagine if we had more if-else statements - it'd be a mess.

Instead, why wouldn't we move it outside of a render method, so it's completely separate?

renderStatus() {
    let status;
    if (flight.cancelled) {
        status = 'Cancelled';
    } else if (flight.arrived) {
        status = 'Arrived';
    } else {
        status = 'Regular';
    }
    return status;
}

render() {
    return (
        <div>
            <p>
                Destination: { flight.destination }
            </p>
            <p>
                Departure time: { flight.departureTime }
            </p>
            <p>
                Arrival time: { flight.arrivalTime }
            </p>
            <p>
                Flight status: { this.renderStatus() }
            </p>
        </div>
    )
}

Our code looks way neater now, right?

All of the examples above were about rendering a simple string based on some boolean values but what would happen if we had to add a different class, or pass a different prop? Logic is the same.

For example, we might want our header element to have relative position in case page's not scrolled, and fixed position otherwise:

render() {
  	return (
    	<header
      		style={{
      			position: (document.body.scrollTop >= 100 ? 'fixed' : 'relative')
      		}}
      	>
      		{
              // content
            }
      	</header>
  	)
}


That was easy, right? Here's a bit more complex example. Let's say we have a button to book a flight unless it's canceled. We can implement it by using if/else syntax:

renderButton() {
    let handleOnPress;
    let buttonClassName;
    let buttonText;
    if (flight.cancelled) {
        buttonClassName = 'button disabled';
        buttonText = 'Cancelled';
    } else {
        buttonClassName = 'button';
        buttonText = 'Book';
        handleOnPress = this.bookFlight
    }
    return (
        <button
            className={buttonClassName}
            onPress={handleOnPress}
        >
            { buttonText }
        </button>
    )
}

We can also use ternary expressions to have the same result as the one produced by the code above:

renderButton() {
    // for className, you can also use this:
    // `button ${flight.cancelled ? 'disabled' : ''}`
    return (
        <button
            className={flight.cancelled ? 'button disabled' : 'button'}
            onPress={flight.cancelled ? null : this.bookFlight}
        >
            { 
                flight.cancelled ?
                    'Cancelled'
                    :
                    'Book'
            }
        </button>
    )
}

If you just want to render/pass something if the condition is fulfilled, you can also write it this way:

render() {
    return (
        <p>
            {
                // condition && what_to_render
            }
            { 
                flight.cancelled && 'Cancelled'
            }
        </p>
    )
}


Conditional rendering inside for loop

When rendering a list of items, you might want to render them differently based on some condition. For example, you might want to add grey background to all the even items. How to do this? You can either use ternary expression or standard if/else, both will work! Remember that it's a function like any other!  Here's a small example:

 

render() {
  return (
    <div>
    {
      this.state.list.map((item, index) => {
                    // if even, render grey background
                    if (index % 2 === 0) {
                      // don't forget to return what you want to render!
                      return (
                        <div style={{backgroundColor: 'grey'}}>
                          {item.name}
                        </div>
                      );
                    } else {
                      // you can also use ternary expression
                      return (
                        <div style={item.expired ? {backgroundColor: 'red'} : null}>
                          {item.name}
                        </div>
                      );
                    }
                  })
    }
    </div>
);
}


Of course, this mapping function can be extracted outside of render method, for increased readability. 


Switch Statement

We've been talking about if-else, but conditioning can, also, be done with a switch statement. Let's say that, instead of the boolean attributes for canceled and arrived, we have one status attribute. Of course, we can't just type something like this:

render() {
    return (
        <p>
            {
                // this will raise an error
            }
            { 
                switch(flight.status) {
                    case 'cancel':
                        return "Cancelled";
                    case 'arrive':
                        return "Arrived";
                    default:
                        return "Regular";
                }
            }
        </p>
    )
}

For switch, there's no neat way to do it directly in return statement. We can, of course, use an immediately-invoked function containing a switch, but it's neither practical nor does it look nice. To make the switch above work, just move it to some function outside of render method:

renderStatus() {
    switch(flight.status) {
        case 'cancel':
            return "Cancelled";
        case 'arrive':
            return "Arrived";
        default:
            return "Regular";
    }
}
render() {
    return (
        <p>
            { 
                this.renderStatus()
            }
        </p>
    )
}

Of course, switch can also be specified in a render method, above the return statement.

Just remember not to use 'return' in cases, but a 'break':

render() {
    let status;
    switch(flight.status) {
        case 'cancel':
            status = "Cancelled";
            break;
        case 'arrive':
            status = "Arrived";
            break;
        default:
            status = "Regular";
            break;
    }
    return (
        <p>
            { status }
        </p>
    )
}

Now you're completely ready to do conditioning in React! Go ahead and try these out, make that code you've been struggling with for hours finally work properly!

If you already knew how to use if-else and switch in React, we hope you still enjoyed the article and freshened up your knowledge a bit.

Thank you for your time!

Next time, we'll be talking about props!

Deploy code to production now. Release to users when ready. Learn how to separate code deployment from user-facing feature releases with LaunchDarkly.

Topics:
react ,javascript ,web dev ,react jsx

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}