Press "Enter" to skip to content

Conditional Rendering in React

React’s declarative rendering approach lets you quickly write rich components combining layout, presentation, and logic. However, it can make it more complicated to conditionally render UI sections. Here’s a few methods you can use to show components on-demand.

Understanding the Problem

Traditional templating systems make it easy to implement conditional rendering. Here’s how you might do that in Handlebars, a JavaScript templating engine:

<div class="profile">
{{#if user}}
<p>You are logged in!</p>
{{else}}
<a href="/login">Login</a>
</div>
{{/if}}

When working in React, you’ll generally be writing JSX. Although JSX looks like HTML, it’s transpiled by React’s build process into regular JavaScript. It ends up as a series of React.createElement() calls.

That means you can’t use unaltered JavaScript conditionals inside JSX. Trying to do something like this will cause a compilation error:

const MyComponent = props => {
    return (
        <div>
            if (props.user) {
                <p>You are logged in!</p>
            }
            else <a href="/login">Login</a>
        </div>
    );
};

If statements in JSX require a little more thought. There’s several approaches you can select from. The option you choose will vary depending on the complexity of the condition, whether there’s an else branch, and whether it will impair the readability of your code.

Lifting out of JSX

The most basic way of fixing the above code is to lift the if out of the return statement:

const MyComponent = props => {
    if (props.user) {
        return <p>You are logged in!</p>;
    }
    else {
        return <a href="/login">Login</a>;
    }
};

The condition has been removed from the JSX. Two independent JSX nodes are used instead, with the one to return determined by an if statement in the function’s body. This approach is clearly understandable and keeps the two branches completely separate.

Using Conditional Expressions

The above solution will usually only work in the very simplest components. You tend to end up duplicating code, such as the top-level <div> present in both the JSX nodes in the example.

Most of the time, you’ll need something more elegant. JSX supports JavaScript expressions that are wrapped in curly braces ({}). You can use boolean comparisons and the ternary operator to achieve inline conditional rendering.

const MyComponent = props => {
    return (
        <div>
            {props.user ? <p>You are logged in!</p> : <a href="/login">Login</a>}
        </div>
    );
};

This example works as intended without any duplication of code. When the user is authenticated, the logged-in text will be displayed. When the user is logged out, the expression evaluates to false so that the login link appears.

Inline expressions are the most commonly used JSX conditional rendering technique. They can be cognitively demanding, though, especially if the true and false return values are themselves expressions. When an expression becomes unwieldy, you can span it across multiple lines. This can improve readability and help keep your file within the line length limits enforced by your linter.

Scenarios Where There Is No “Else”

Let’s now adapt the example above by removing the “you are logged in” text. Our product manager decided it’s not necessary in this section of the app. The container <div> should now be empty when the user is logged in.

React lets you return null to indicate there is nothing to render. Adjust the component’s conditional expression accordingly.

const MyComponent = props => {
    return (
        <div>
            {props.user ? null : <a href="/login">Login</a>}
        </div>
    );
};

React also supports false with the same meaning as null. This means you can shorten the above by using JavaScript’s && (and) operator to do a boolean comparison.

const MyComponent = props => {
    return (
        <div>
            {!props.user && <a href="/login">Login</a>}
        </div>
    );
};

The left-hand side of the expression will evaluate to false when the user is logged in. As the two sides are joined with an and, the overall expression also evaluates to false. Consequently, nothing is rendered when the user is logged in.

When logged out, the left-hand side evaluates to true. The right-hand side will always be truthy as it resolves to a JavaScript object when the JSX is transpiled. This form of evaluation returns the right-hand side of the expression so that the login link ends up being rendered.

JavaScript evaluations are “short-circuited.” This means that the JSX on the right-hand side won’t be needlessly constructed if the left-hand expression evaluates to false.

Conditional Prop Values

You can make the values of props conditional using embedded expressions in the same style as those shown above. Use a conditional or a ternary evaluation to determine the value to supply. Returning a value of undefined is equivalent to not specifying the prop.

const MyComponent = props => {
    return (
        <div>
            <a href={(props.user.loggedIn === true) ? "/dashboard" : "/home"}>
                Home
            </a>
        </div>
    );
};

In this example, the destination of the “Home” link is dynamically adjusted depending on whether the user is logged in. Remember that a component’s props in JSX are transpiled to a plain JavaScript object, which is why this technique works. You are really writing the following:

React.createElement("a", {
    href: (props.user.loggedIn === true) ? "/dashboard" : "/home"
});

JSX is merely a JavaScript syntax extension that lets you declare React components in a form reminiscent of HTML.

Conditionals Using Logic Components

Another way of achieving conditional rendering is to incorporate so-called “logic” components into your project. These are simple components that only render their children if a condition is met.

const IfComponent = props => {
    if (props.condition) return props.children;
    else return null;
}
 
const MyComponent = props => (
    <IfComponent condition={props.user.isLoggedIn}>
        <a href="/logout">Logout</a>
    </IfComponent>
);

This pattern can make the code in your render() function more intuitive. However, there’s one big problem—the a element will always be rendered, even if the if condition isn’t met. You could solve this by adapting IfComponent so that it calls a function instead of rendering children directly.

const IfComponent = props => {
    if (props.condition) return props.renderChildren();
    else return null;
}
 
const renderContent = () => <a href="/logout">Logout</a>;
 
const MyComponent = props => (
    <IfComponent
        condition={props.user.isLoggedIn}
        renderContent={renderContent} />
);

Now the a element only gets constructed when the condition is actually met. This reduces unnecessary rerenders, which will improve performance when using complex components.

A variation on this pattern is to create a higher-order component (HOC). This allows you to wrap a component with conditional functionality.

const ifHoc = (condition, component) => {
    return props => {
        if (condition()) return component(props);
        else return null;
    };
}
 
const LogoutLink = () => <a href="/logout">Logout</a>;
 
const LogoutLinkOnlyWhenLoggedIn = ifHoc(props => props.loggedIn, LoginLink);
-
const ComponentUsingLoginLink = props => (
    <LogoutLinkOnlyWhenLoggedIn loggedIn={props.user.isLoggedIn} />
);

This approach can be a little harder to understand at first. It’s best when you want to keep the component to be rendered completely separate to the conditional logic. It also enables reuse of complex logic, as any component can be wrapped with ifHoc(). The HOC wraps the original component and only renders it when the passed-in conditional functional returns true.

Performance Issues

A few general performance considerations apply to all conditional rendering in React. The most important is to limit rerendering as far as is practicable. Try not to replace massive chunks of UI within presentational components. Too much rerendering can quickly create a “feels slow” sensation.

Similarly, be aware that your conditional expressions will usually be evaluated each time your component renders. If the conditions themselves are complex (such as mapping an array of objects into new objects), this too can create a slowdown, especially on low-end hardware.

Conclusion

React requires you to approach conditional rendering slightly differently to traditional templating systems. This is because JSX only looks like HTML. It’s transpiled back to JavaScript objects, which are then used with React funcion calls.

Nonetheless, you have a variety of options available when you need to conditionally render a component. The most straightforward option is usually to write conditional expressions inside your JSX, either using && or the ternary syntax. You can fallback to a real if at the root of your render() method, or adopt a higher-order component if JSX expressions would make your rendering flow harder to understand.

This post was originally published on this site

Be First to Comment

Leave a Reply

Your email address will not be published. Required fields are marked *