React JSX - How to do it the right way - Part II

Kolosek 发布于7天前 阅读38次
0 条评论

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 will not 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 2 javascript is pretty flexible, we still can not 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?

Of course, we can do something like this:

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

This 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 we had more if-else statements - it'd be a mess.
Instead, why would not we 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 could have happened if we had to add a different class, or pass a different prop? Logic is the same.

Let's say we have a button to book a flight unless it's canceled:

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 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 fullfilled, you can also write it this way:

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

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 not 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  immediately-invoked function  containing a switch, but it's neither practical or 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 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!

Originally published on kolosek.com .

需要 登录 后回复方可回复, 如果你还没有账号你可以 注册 一个帐号。