Conditional Rendering in React

Real applications rarely show the exact same UI to everyone at all times. A logged-in user sees a dashboard; a logged-out user sees a login button. A page shows a loading spinner while data is fetching, and the actual content once it arrives. This kind of “show this, or show that, depending on a condition” logic is called conditional rendering, and React gives you several clean ways to handle it.

Why You Can’t Use if Directly Inside JSX

In an earlier post, you learned that JSX only accepts expressions inside curly braces {}, not statements. Since if is a statement (not an expression), this won’t work:

jsx
function Greeting({ isLoggedIn }) {
  return (
    <div>
      {if (isLoggedIn) {          // ❌ This will throw a syntax error
        <h1>Welcome back!</h1>
      }}
    </div>
  )
}

Instead, React relies on a few different patterns — using if statements outside the JSX, ternary operators, and logical operators inside the JSX. Let’s go through each one.

Method 1: if / else Outside the Return Statement

The most straightforward approach is to use a regular if statement above your return, and simply return different JSX for each case.

jsx
function Greeting({ isLoggedIn }) {
  if (isLoggedIn) {
    return <h1>Welcome back!</h1>
  }
  return <h1>Please log in.</h1>
}

This works well when the two outcomes are completely different pieces of UI. It’s readable and easy to follow, especially for beginners.

Method 2: Ternary Operator (condition ? A : B)

When you want to conditionally render something inside a larger block of JSX (rather than returning entirely different UI), the ternary operator is a common choice:

jsx
function Greeting({ isLoggedIn }) {
  return (
    <div>
      {isLoggedIn ? <h1>Welcome back!</h1> : <h1>Please log in.</h1>}
    </div>
  )
}

This reads as: “if isLoggedIn is true, render the first element; otherwise, render the second.” Ternaries work well for simple two-way conditions, but avoid nesting multiple ternaries inside each other — it quickly becomes hard to read.

Avoid this (nested ternaries):

jsx
{status === "loading" ? <Spinner /> : status === "error" ? <ErrorMessage /> : <Content />}

If you find yourself nesting ternaries like this, it’s usually a sign you should switch to an if/else chain or a switchstatement instead.

Method 3: Logical AND (&&) Operator

Very often, you only want to render something if a condition is true, and render nothing at all otherwise. For this, the && operator is the idiomatic React pattern:

jsx
function Notifications({ count }) {
  return (
    <div>
      <h2>Inbox</h2>
      {count > 0 && <p>You have {count} new messages.</p>}
    </div>
  )
}

Here’s why this works: in JavaScript, && evaluates the left side first. If it’s false (or falsy), the expression short-circuits and returns that falsy value immediately, without ever evaluating the right side. React simply renders nothing when it receives false, null, or undefined. If the left side is true, JavaScript evaluates and returns the right side — in this case, the JSX to render.

A Common Pitfall with &&

Be careful when the condition is a number, especially 0:

jsx
function Cart({ itemCount }) {
  return (
    <div>
      {itemCount && <p>You have {itemCount} items in your cart.</p>}
    </div>
  )
}

If itemCount is 0, this expression evaluates to 0 (not false), and — unlike false, null, or undefinedReact will actually render the number 0 on the screen. You’d see a stray “0” floating in your UI, which is rarely what you want.

Fix: Convert the condition to an explicit boolean using a comparison:

jsx
{itemCount > 0 && <p>You have {itemCount} items in your cart.</p>}

This is a subtle bug that catches a lot of beginners (and even experienced developers), so it’s worth remembering.

Method 4: Using Variables to Store JSX

For more complex conditions, it can be cleaner to compute the JSX in a variable first, then render that variable in your return statement.

jsx
function StatusMessage({ status }) {
  let message

  if (status === "loading") {
    message = <p>Loading...</p>
  } else if (status === "error") {
    message = <p>Something went wrong.</p>
  } else if (status === "success") {
    message = <p>Data loaded successfully!</p>
  }

  return <div>{message}</div>
}

This approach scales much better than nested ternaries when you have three or more possible outcomes, since each condition is clearly separated and easy to read.

Method 5: Switch Statements for Multiple Conditions

When you have many possible states, a switch statement (used outside the JSX) can be even clearer than a long if/else ifchain:

jsx
function StatusMessage({ status }) {
  switch (status) {
    case "loading":
      return <p>Loading...</p>
    case "error":
      return <p>Something went wrong.</p>
    case "success":
      return <p>Data loaded successfully!</p>
    default:
      return <p>Unknown status.</p>
  }
}

Including a default case is good practice — it ensures your component always renders something sensible, even for states you haven’t explicitly handled.

Conditionally Rendering Nothing

Sometimes you genuinely want a component to render nothing under certain conditions. Returning null tells React not to render any output for that component:

jsx
function WarningBanner({ show }) {
  if (!show) {
    return null
  }
  return <div className="banner">Warning: Something needs your attention!</div>
}

This is a common pattern for banners, modals, and alerts that should only appear under specific circumstances.

A Practical Example: Combining Multiple Techniques

Here’s a slightly more realistic example that combines several patterns you’ve just learned — showing a loading state, an error state, or the actual data, depending on the situation:

jsx
function UserProfile({ isLoading, error, user }) {
  if (isLoading) {
    return <p>Loading profile...</p>
  }

  if (error) {
    return <p>Failed to load profile: {error}</p>
  }

  return (
    <div>
      <h2>{user.name}</h2>
      <p>{user.email}</p>
      {user.isPremium && <span className="badge">Premium Member</span>}
    </div>
  )
}

This pattern — checking for loading and error states before rendering the “happy path” — is extremely common in real-world React applications, especially once you start fetching data from APIs (which we’ll cover in a later post).

Common Mistakes Beginners Make

  1. Trying to use if statements directly inside JSX curly braces, which causes syntax errors.
  2. Nesting too many ternary operators, making the code hard to read and maintain.
  3. Using && with a number that could be 0, accidentally rendering a stray “0” on the screen.
  4. Forgetting a default case in switch-based rendering, leaving certain states unhandled.
  5. Returning undefined instead of null — while both usually work, returning null explicitly is the clearer and more intentional choice for “render nothing.”

Recap

In this post, you learned:

  • Why if statements can’t be used directly inside JSX, and how to work around that
  • How to use if/else, ternary operators, and the && operator for conditional rendering
  • A common pitfall with && and numeric values like 0
  • How to use variables and switch statements for handling multiple possible UI states
  • How to render nothing at all using return null

Conditional rendering handles what to show, but many UIs also need to display collections of data — like a list of products, comments, or search results. In the next post, we’ll cover Lists and Keys, and why that mysterious key prop you’ve seen in earlier examples actually matters.

Share.
Leave A Reply

Exit mobile version