React Conditional Rendering

By mastering this essential technique, you can control exactly which UI elements are displayed in your components, streamlining your component logic and creating user interfaces that respond seamlessly to different scenarios. Whether you want to show a Log In button or a Welcome Back message based on user authentication or conditionally render loading states while data is being fetched, react conditional rendering equips you with the tools to build dynamic and engaging React applications.

React-Conditional-Rendering
Table of Contents

Fundamentals of Conditional Rendering

In React, conditional rendering is like a traffic light for your UI elements – it decides which ones get to show and which ones wait their turn. Imagine you want to display a logout button only if a user is logged in or a loading spinner while data is being fetched. To achieve this, conditional rendering relies on JavaScript logic and expressions, such as if/else statements or the ternary operator, embedded directly within your JSX code. By controlling the conditions under which elements are displayed, you create React components that intelligently adapt to changing data or user interactions.

React’s Conditional Rendering

In React applications, you often want your components to display different content based on certain conditions. This is where conditional rendering comes in. It empowers you to control what parts of a component’s UI are shown to the user, creating dynamic and interactive experiences.

Why is it Important?

Imagine an e-commerce website. You wouldn’t want to show the “Add to Cart” button if the product is out of stock. Here, conditional rendering allows you to display the button only when the product has inventory.

Example: Login vs. Welcome Message

function UserGreeting(props) {
    return <h1>Welcome Back, {props.username}!</h1>;
}

function GuestGreeting(props) {
    return <h1>Please sign up or log in.</h1>;
}

function Greeting(props) {
    const isLoggedIn = props.isLoggedIn;  // Assuming a prop for login state
    if (isLoggedIn) {
        return <UserGreeting username={props.username} />;
    } else {
        return <GuestGreeting />;
    }
}

Explanation

  • Lines 1-3: The UserGreeting component displays a welcome message with the username passed as a prop.
  • Lines 5-7: The GuestGreeting component displays a message prompting the user to sign up or log in.
  • Lines 9-16: The Greeting component:
    • Line 10: Manages a prop (isLoggedIn) to determine login status.
    • Line 11: Uses an if statement to check the login state.
    • Line 12: If logged in, returns the UserGreeting component with username prop.
    • Line 13: If not logged in, returns the GuestGreeting component.

This example demonstrates how conditional rendering allows you to choose which greeting component to display based on the isLoggedIn prop, creating a dynamic user experience.


Common Conditional Rendering Techniques

React offers a diverse toolkit for conditional rendering, providing flexibility in controlling what your components display. Simple if/else statements within JSX handle straightforward conditions. For concise rendering within the JSX itself, the logical AND operator (&&) shines. When you need a compact alternative for if/else, the ternary operator offers a more compressed syntax. Lastly, returning null from your component’s render method allows you to prevent elements from rendering entirely based on certain conditions.

if and else in React

The if and else statements are fundamental building blocks for conditional rendering in React. They allow you to execute code based on whether a certain condition is true or false, controlling which parts of your UI are displayed.

Understanding if and else

  • The if statement checks a condition. If the condition is true, the code within the if block is executed.
  • The optional else block provides alternative code to run if the condition in the if statement is false.

Example: Displaying Stock Status

function ProductCard(props) {
    const inStock = props.inStock; // Assuming a prop for stock status

    return (
        <div>
            <h2>{props.name}</h2>
            {inStock ? (  /* if statement */
                <p>In Stock!</p>
            ) : (  /* else block */
                <p>Out of Stock</p>
            )}
        </div>
    );
}

Explanation

  • Lines 1-2: The ProductCard component receives a inStock prop indicating product availability.
  • Lines 5-13: Renders product details within a div.
  • Lines 7-11: The if statement:
    • Line 7: Checks the inStock prop using a conditional expression.
    • Line 8: If inStock is true, displays an "In Stock" message.
    • Line 9: The else block runs if inStock is false.
    • Line 10: Displays an "Out of Stock" message.

This example demonstrates how if and else statements can be used within JSX to conditionally render content based on a product’s stock status. The appropriate message is displayed depending on the inStock prop value.

Logical AND (&&) Operator in React

The logical AND operator (&&) offers a concise way to conditionally render elements directly within JSX. Here’s how it works:

  • The expression to the left of the && operator is evaluated first.
  • If the left expression is true, the expression to the right of the && operator is evaluated and its result is rendered.
  • If the left expression is falsy, the expression to the right is skipped, and nothing is rendered.

Example: Conditional Display of Error Message

function FormError(props) {
    return (
        <div className="error-message">
            <p>{props.errorMessage}</p>
        </div>
    );
}

function MyForm(props) {
    const hasError = props.hasError;  // Assuming a prop for error state

    return (
        <div>
            {/* ... other form elements ... */}
            {hasError && <FormError errorMessage="Please correct the error above." />}
        </div>
    );
}

Explanation

  • Lines 1-7: The FormError component displays an error message.
  • Lines 9-18: The MyForm component:
    • Line 10: Manages a prop (hasError) indicating error state.
    • Line 15: Uses the logical AND operator:
      • Left side: hasError is evaluated for truthiness.
      • Right side: <FormError ... /> will only be rendered if hasError is true.

This example demonstrates how the logical AND operator allows for the conditional rendering of an error message (FormError) only when in the form (hasError is true). This technique is especially useful for concisely displaying elements based on specific conditions.

Ternary Operator in React

The ternary operator (sometimes called the conditional operator) provides a compact way to write conditional expressions within JSX. It’s a shorthand for simple if/else statements.

Syntax of Ternary Operator

condition ? expressionIfTrue : expressionIfFalse
  • If the condition is true, the expressionIfTrue is evaluated and returned.
  • If the condition is false, the expressionIfFalse is evaluated and returned.

Example: Displaying a Button Based on User Role

function MyComponent(props) {
    const isAdmin = props.isAdmin;  // Assuming a prop for user role

    return (
        <div>
            {isAdmin ? (
                <button>Show Admin Settings</button>
            ) : (
                <p>You are not an admin.</p>
            )}
        </div>
    );
}

Explanation

  • Lines 1-2: The MyComponent component receives an isAdmin prop for user role.
  • Lines 5-12: Renders content within a div.
  • Lines 6-10: The ternary operator:
    • Line 6: Checks the isAdmin prop using a conditional expression.
    • Line 7: If isAdmin is true, an "Show Admin Settings" button is rendered.
    • Line 9: If isAdmin is false, a message indicating non-admin status is displayed.

Here, the ternary operator offers a more concise way to conditionally render the button based on the user’s admin role compared to a traditional if and else statement.

Hiding Elements with null in Conditional Rendering

React doesn’t render elements that evaluate to null. This behavior can be used for conditional rendering, which completely removes elements from the UI when certain conditions are unmet.

Using null for Early Returns

  • In your component’s return statement, you can conditionally return null to prevent any further JSX code from being evaluated.
  • This effectively hides the element from the rendered output.

Example: Conditional Display of Loading Spinner

function DataLoader(props) {
    const isLoading = props.isLoading;  // Assuming a prop for loading state

    return (
        <div>
            {isLoading ? (  /* Conditional expression */
                <p>Loading data...</p>
            ) : (
                <div>  /* Content to be displayed after loading */
                    <h2>Fetched Data</h2>
              /* ... other content ... */
                </div>
            )}
        </div>
    );
}

Explanation

  • Lines 1-2: The DataLoader component receives an isLoading prop for data loading status.
  • Lines 4-15: Renders content within a div.
  • Lines 6-14: The conditional expression:
    • Line 6: Checks the isLoading prop.
    • Lines 7-8: If isLoading is true:
      • A "Loading data..." message is displayed.
      • The rest of the code (lines 9-13) is skipped due to the early return.
    • Lines 9-13: If isLoading is false:
      • The actual data content (<h2>Fetched Data</h2>) is rendered.

This example demonstrates how returning null conditionally based on the isLoading prop allows you to display a loading message. At the same time, data is being fetched, and then it is completely hidden once the data is loaded, resulting in a cleaner UI transition.


Advanced Conditional Rendering Strategies

While basic techniques cover most scenarios, React offers flexibility for complex conditional rendering. State management with the useState hook lets you track dynamic data to control which elements are displayed. Element variables enhance readability by storing JSX outside the main return statement. Immediately Invoked Function Expressions (IIFEs) provide a less common option, though caution is advised for cleaner code. Further, by passing data through props, parent components can influence the UI rendering within their child components.

State Management: Dynamic Conditional Rendering

For complex conditional rendering scenarios, React’s state management capabilities become crucial. The useState hook allows you to manage dynamic data within your component, and this data can then be used to control which elements are displayed.

Why State Management?

Imagine a to-do list application. You wouldn’t want to display a “Complete Task” button unless a specific task is marked as incomplete. State management with useState helps track task completion status and conditionally render the button based on that state.

Example: Task Status and Button

import { useState } from 'react';

function TaskItem(props) {
    const [isCompleted, setIsCompleted] = useState(props.initialCompleted);  // Initial state from props

    const handleToggleCompletion = () => {
        setIsCompleted(!isCompleted);
    };

    return (
        <div className="task-item">
            <p>{props.taskText}</p>
            {isCompleted ? (
                <p>Completed</p>
            ) : (
                <button onClick={handleToggleCompletion}>Complete Task</button>
            )}
        </div>
    );
}

Explanation

  • Line 1: Imports the useState hook from React.
  • Lines 3-4: The TaskItem component:
    • Manages a state variable isCompleted using useState, initialized with the initialCompleted prop.
  • Lines 6-8: Defines a handleToggleCompletion function to update the isCompleted state on button click.
  • Lines 11-19: Renders the task details within a div.
  • Lines 13-17: Conditional rendering based on the isCompleted state:
    • If isCompleted is true (task completed):
      • Displays a "Completed" message (line 14).
    • If isCompleted is false (task incomplete):
      • Renders a "Complete Task" button with an onClick handler (lines 16-17).

This example showcases how useState manages the isCompleted state, and the conditional rendering logic within JSX uses this state to determine whether to display the “Completed” message or the “Complete Task” button. This approach ensures that the button is only shown when the task is not marked as complete.

Conditional Rendering with Element Variables

While conditional rendering within JSX is powerful, it can sometimes become cluttered with complex logic. Element variables offer an alternative approach for improved readability and organization.

The Idea Behind Element Variables

  • You can store JSX elements (like divs, buttons, or other components) within variables.
  • These variables can then be conditionally assigned values based on certain conditions.
  • Finally, the assigned variable is rendered within your JSX return statement.

Benefits of Element Variables

  • Isolates conditional logic outside of the main return statement, making JSX cleaner.
  • Improves code readability and maintainability for complex conditional rendering scenarios.

Example: Conditional Content Based on User Type

function UserDashboard(props) {
    const userType = props.userType;  // Assuming a prop for user type

    let content;

    if (userType === "admin") {
        content = (
            <div>
                <h2>Admin Dashboard</h2>
                {/* ... Admin-specific content ... */}
            </div>
        );
    } else {
        content = (
            <div>
                <h2>User Dashboard</h2>
                {/* ... User-specific content ... */}
            </div>
        );
    }

    return (
        <div>
            {content}
        </div>
    );
}

Explanation

  • Lines 1-2: The UserDashboard component receives a userType prop.
  • Line 4: Declares a content variable to hold the JSX element.
  • Lines 6-20: Conditional assignment to the content variable based on userType:
    • Lines 7-12: If userType is "admin", sets content to admin dashboard JSX.
    • Lines 14-19: If userType is not "admin" (user), sets content to user dashboard JSX.
  • Lines 22-27: Renders the content variable within the main div.

Here, element variables enhance readability. The conditional logic for assigning content is separated from the main return statement, resulting in cleaner JSX within the render function.

IIFEs for Conditional Rendering (Use with Caution)

Immediately Invoked Function Expressions (IIFEs) are a JavaScript function construct that can be used for conditional rendering in React, but it’s generally considered a less common approach.

What are IIFEs?

  • IIFEs are functions invoked (called) immediately after being defined.
  • They can encapsulate logic and potentially return a JSX element for conditional rendering.

Why Use IIFEs with Caution?

  • While technically possible, using IIFEs for conditional rendering can make code harder to read and maintain compared to other techniques like if statements or element variables.
  • React’s JSX syntax and other built-in features often provide clearer and more idiomatic ways to achieve conditional rendering.

Example: Age Restriction with IIFE (for illustration purposes only)

function AgeGate(props) {
    const minAge = 18; // Assuming a minimum age requirement

    return (
        <div>
            {(function () {
                if (props.age >= minAge) {
                    return (
                        <div>
                            <h2>Welcome!</h2>
                            {/* ... Content for users above minimum age ... */}
                        </div>
                    );
                } else {
                    return <p>Sorry, you must be 18 or older to access this content.</p>;
                }
            })()}
        </div>
    );
}

Explanation

  • Lines 1-2: The AgeGate component receives an age prop and defines a minimum age.
  • Lines 5-19: Renders content within a div.
  • Lines 6-17: An IIFE encapsulates the conditional logic:
    • Lines 7-16: Checks the age prop against the minimum age.
      • If age is sufficient, returns welcome content (lines 8-13).
      • If age is not sufficient, returns an age restriction message (line 15).
  • Line 17: The IIFE is invoked with empty parentheses ( ) to execute it immediately.

Remember: While this example demonstrates IIFEs for conditional rendering, it’s generally recommended to use if statements, element variables, or other more common React patterns for better readability and maintainability.

Props as Triggers

React components often receive data through props. This data can be used to control how child components render their UI elements conditionally, allowing for a more modular and reusable approach to conditional rendering.

Power of Props

Imagine a product listing component that receives a showDiscount prop from its parent. Based on the value of this prop, the product listing can conditionally display a discount message or the regular price.

Example: Price Display with Conditional Discount

function ProductListing(props) {
    const price = props.price;
    const hasDiscount = props.showDiscount; // Assuming a prop for discount

    return (
        <div className="product-listing">
            <h2>{props.name}</h2>
            {hasDiscount ? (
                <p>Discounted Price: ${price * 0.8}</p>  /* Assuming 20% discount */
            ) : (
                <p>Regular Price: ${price}</p>
            )}
        </div>
    );
}

Explanation

  • Lines 1-3: The ProductListing component receives props for product name, price, and showDiscount.
  • Lines 6-14: Renders product details within a div.
  • Lines 8-12: Conditional rendering based on the hasDiscount prop:
    • If hasDiscount is true:
      • Calculates and displays the discounted price (line 9).
    • If hasDiscount is false:
      • Displays the regular price (line 11).

This example showcases how a child component (ProductListing) uses a prop (showDiscount) from its parent to decide whether to display the discounted or regular price. This promotes reusability – the ProductListing component can be used for products with or without discounts based on the prop value passed by the parent.


Considerations and Best Practices

Choosing the most suitable conditional rendering technique depends on the complexity of your logic. For simple scenarios, stick with if/else statements or the logical AND operator for efficiency. Exploring React’s state management tools (like useState) and element variables can improve code readability and organization when conditions become more intricate. Remember to prioritize performance, particularly for complex or frequently updated UI elements – techniques like memoization can help prevent unnecessary re-renders. Always consider the specific requirements of your components to make the best decisions for both usability and performance.

Choosing a Conditional Rendering Approach

React empowers you with various techniques for conditional rendering, but selecting the right one for each situation is crucial. Here’s a breakdown to guide your decision:

Matching Technique to Complexity

Simple if statements or the logical AND operator (&&) often suffice for straightforward conditions. When your conditional logic becomes intricate, state management using useState or element variables for readability is a better choice.

Example: Login Button Visibility (Simple vs. Complex)

Simple Scenario (if statement)

function LoginPage(props) {
    const isLoggedIn = props.isLoggedIn;  // Assuming a prop for login state

    return (
        <div>
            {isLoggedIn ? (  /* Conditional expression */
                <p>Welcome back!</p>
            ) : (
                <button>Login</button>
            )}
        </div>
    );
}

Explanation

  • Lines 1-2: The LoginPage component receives an isLoggedIn prop.
  • Lines 6-9: A simple if statement conditionally displays:
    • A welcome message if logged in (line 7).
    • A login button if not logged in (line 9).

Complex Scenario (useState)

import { useState } from 'react';

function ProfileSettings(props) {
    const [isEditing, setIsEditing] = useState(false);  // Initial editing state

    const handleEditClick = () => {
        setIsEditing(!isEditing);
    };

    return (
        <div>
            <h2>Profile Settings</h2>
            {isEditing ? (
                <div>
                    {/* ... Edit profile form elements ... */}
                    <button onClick={handleEditClick}>Save Changes</button>
                </div>
            ) : (
                <button onClick={handleEditClick}>Edit Profile</button>
            )}
        </div>
    );
}

Explanation

  • Lines 1-3: The ProfileSettings component uses useState to manage an isEditing state.
  • Lines 6-8: Defines a function handleEditClick to toggle the isEditing state.
  • Lines 13-21: Conditional rendering based on isEditing:
    • If isEditing is true (editing mode):
      • Displays edit form elements (line 15) and a "Save Changes" button (line 19).
    • If isEditing is false (not editing):
      • Displays an "Edit Profile" button (line 19).

This example demonstrates two approaches. The simple login scenario uses an if statement for a clear-cut condition. However, for the profile settings with editing functionality, state management with useState is a better choice to handle dynamic user interactions and conditional rendering of edit forms and buttons based on the editing state.

Performance Considerations in Conditional Rendering

While conditional rendering offers flexibility, it’s important to consider performance implications. Here are some tips:

  • Avoid Excessive Re-renders: Unnecessary re-renders due to frequent conditional changes can slow down your application. Techniques like memoization can help prevent unnecessary re-renders of components based on prop or state changes.
  • Choose the Right Approach: Lightweight techniques like if statements or the logical AND operator (&&) are generally performant for simple conditions. Consider useState for state management for more complex scenarios, but be mindful of potential re-renders it might cause.

Example: Memoizing a Loading Message (for illustration purposes only)

import { memo } from 'react';

function LoadingMessage() {
    return <p>Loading data...</p>;
}

const MemoizedLoadingMessage = memo(LoadingMessage);

function DataLoader(props) {
    const isLoading = props.isLoading;

    return (
        <div>
            {isLoading ? <MemoizedLoadingMessage /> : (
                {/* ... Content to be displayed after loading */ }
            )}
        </div>
    );
}

Explanation

  • Lines 1-5: A simple LoadingMessage component displays a loading message.
  • Line 7: The LoadingMessage component is wrapped with memo from React to memoize it.
  • Lines 9-10: The DataLoader component receives an isLoading prop.
  • Lines 14-15: Conditional rendering:
    • If isLoading is true: Renders the memoized MemoizedLoadingMessage component. Memoization helps prevent unnecessary re-renders of the loading message even if isLoading changes frequently.

Remember: While memoization can be helpful, it’s not a silver bullet. Use it strategically for components that are expensive to render and only re-render when their props truly change.

Avoiding Unnecessary Re-renders

Conditional rendering is powerful, but excessive re-renders can slow your React application. Here’s how to minimize them:

  • Memoization: Wrap frequently used components with React’s memo higher-order component. This helps prevent re-renders if their props haven’t changed, even if the component that renders them re-renders.
  • useState with Care: While useState is great for dynamic data, be mindful of how you update it. Consider combining state updates or batching updates to reduce unnecessary re-renders based on state changes.

Example: Memoizing a Button Based on Prop (for illustration purposes only)

import { memo } from 'react';

function PrimaryButton(props) {
    return <button className="primary">{props.text}</button>;
}

const MemoizedPrimaryButton = memo(PrimaryButton);

function FeatureItem(props) {
    const isActive = props.isActive; // Assuming a prop for feature state

    return (
        <div className="feature-item">
            <h2>{props.title}</h2>
            {isActive ? (
                <MemoizedPrimaryButton text="Enabled" />
            ) : (
                <MemoizedPrimaryButton text="Disabled" />
            )}
        </div>
    );
}

Explanation

  • Lines 1-5: A simple PrimaryButton component renders a button with text.
  • Line 7: The PrimaryButton component is wrapped with memo to memoize it.
  • Lines 9-10: The FeatureItem component receives an isActive prop for feature state.
  • Lines 15-19: Conditional rendering with memoized buttons:
    • If isActive is true: Renders a memoized button with "Enabled" text (line 16).
    • If isActive is false: Renders a memoized button with "Disabled" text (line 18).

By memoizing the PrimaryButton, unnecessary re-renders of the button are prevented, even if the FeatureItem re-renders due to changes in isActive. This helps optimize performance.