DEV Community

Cover image for 4 Ways to Render JSX Conditionally in React
Rasaf Ibrahim
Rasaf Ibrahim

Posted on

4 Ways to Render JSX Conditionally in React

Rendering JSX conditionally is a very common and essential work in React. There are 4 ways in which we can render JSX conditionally in React:

  1. Ternary Operator

  2. Logical Operator

  3. if, else, else if

  4. Switch Statement

 

Generally, developers don't use if else or switch statement inside JSX for conditional rendering. Because it takes more lines of code with if else or switch statement than ternary operator or logical operator. But when you have more than two conditions to deal with, you have to use if else or switch statement.

 

Ternary Operator

 

function TernaryOperator() {

  return (
    <>     
        {
            /* Ternary Operator */

            'a'==='a' ? <p>Hi</p> : <p>Bye</p>
        } 
    </>
  )

}

export default TernaryOperator

Enter fullscreen mode Exit fullscreen mode

Explanation

Only if the condition 'a'==='a' is true, <p>Hi</p> will be rendered one the screen. Otherwise, <p>Bye</p> will be rendered on the screen.

 

Note:

It's not a very realistic example because you would never compare 'a'==='a' in a real-world application. But this comparison is not the main point here. The point is the use of the ternary operator.

 

Logical Operator

 

AND && (Logical Operator)

 

function LogicalAnd() {

  return (
    <>     
        {
            /* Logical 'AND' Operator*/

            'a'==='a' && <p>Hi</p>
        } 
    </>
)

}

export default LogicalAnd
)
Enter fullscreen mode Exit fullscreen mode

Explanation

Only if the condition 'a'==='a' is true, <p>Hi</p> will be rendered on the screen.

 

OR || (Logical Operator)

 

function LogicalOR({name, labelText}) {

  return (
    <>       
        /* Logical 'OR' Operator*/
         {labelText || name}      
    </>
  )
}

export default LogicalOR
Enter fullscreen mode Exit fullscreen mode

Explanation:

If labelText and name both props are passed into this component, then labelText will be rendered on the screen. But if only one of them (name or labelText ) is passed as a prop, then that passed prop will be rendered on the screen.

 

NOT ! (Logical Operator)

 


function LogicalNOT ({name})  { 

    /* Logical NOT Operator */
    if (!name) {  
      return null; 
    }              


    return <p>Hi! My name is {name}.</p>;
  }

 export default LogicalNOT

Enter fullscreen mode Exit fullscreen mode

Explanation

Only if the name prop is passed then <p>Hi! My name is {name}.</p> will be rendered on the screen, otherwise, nothing will render on the screen.

 

Note

if (!name) { return null }, returning early like this is known as Early Return. Early Return is also called Guard Clause or Bouncer Pattern.

 

if, else, else if

 

function IfElse() {

    return ( 
      <>     
          {
            /*If else condition within an anonymous function*/

              (() => {
                  if('a'==='b') {
                          return (
                              <p>Hi</p>
                          )
                      } else if ('b'==='b') {
                          return (
                          <p>Hello</p>
                          )
                      } else {
                          return (
                              <p>Bye</p>
                          )
                      }
              })()  
          }  
      </>  
    )


}

export default IfElse
Enter fullscreen mode Exit fullscreen mode

Note:

Have to use an anonymous function (also need to immediately invoke the function )

 

Switch Statement

 

function SwitchStatement() {

  return ( 
    <>     
        {

           /*Switch Statement within an anonymous function*/

            (() => {
                switch(true) {

                    case('a'==='b'): {
                            return (
                                <p>Hello</p>
                            )
                        }
                    break;

                    case('a'==='a'): {
                        return (
                            <p>Hi</p>
                        )
                    }
                    break;

                    default: {
                            return (
                                <p>Bye</p>
                            )
                        }
                    break;
                    }
            })()  
        }  
    </>  
)

}

export default SwitchStatement
Enter fullscreen mode Exit fullscreen mode

Note:

Have to use an anonymous function (also need to immediately invoke the function )

 

That's it.😃 Thanks for reading.🎉

Discussion (37)

Collapse
danwalsh profile image
Dan Walsh

One more approach you might consider adding to your list is the “guard clause”:

const MyComponent = ({name}) => { 
  if (!name) {   // 👈
    return null; // 👈 guard clause
  }              // 👈

  return <p>Hi! My name is {name}.</p>;
};

export default MyComponent;
Enter fullscreen mode Exit fullscreen mode

This conditional rendering tactic will prevent the entire component from rendering (including any unnecessary <div>s) if your conditions are not met.

Abstracting the logic from your return() statements in this way also helps by avoiding confusing nested conditionals, improving the readability of your code.

Collapse
lukeshiru profile image
Luke Shiru

It depends on the reader. For me this:

const MyComponent = ({ name }) => { 
  if (!name) {
    return null;
  }

  return <p>Hi! My name is {name}.</p>;
};
Enter fullscreen mode Exit fullscreen mode

Is far less readable than this:

const MyComponent = ({ name }) =>
  name ? <p>Hi! My name is {name}.</p> : null;
Enter fullscreen mode Exit fullscreen mode

Not to mention that folks using this style, more often than not, write "scape returns" all over the function, instead of having a single return, which makes way harder than it should to follow the logic of the function.

Collapse
danwalsh profile image
Dan Walsh • Edited on

In this extremely limited example, I’d agree that boiling the component down to a single ternary is fine. Most real world components however will contain more than a single truthy test and a single line of JSX in their return.

Guard clauses (or early returns) are great for refactoring nested conditional trees. Should you use them for every component? No. Does it meet the author’s post criteria of “Ways to Render JSX Conditionally in React”? Yes, I’d say so.

I’m not familiar with “scrape returns”, and I can’t seem to find any examples online. Can you elaborate, please?

Thread Thread
moopet profile image
Ben Sinclair

They said, "scape" not "scrape" so I'm assuming it's either a typo for "Escape" or slang for it.

I can see how "escape" could sound a bit cooler than "return early" :)

Thread Thread
danwalsh profile image
Dan Walsh

Thanks, @moopet! Complete misread on my behalf! 😅

Thread Thread
lukeshiru profile image
Luke Shiru • Edited on

Is not "scrape" is "escape" (I had a typo and forgot the "e") and I put that in quotes because I was just saying I don't like to use return as a way of "going out/escaping" of a function. Generally if you need an early return, that's a sign that you're putting too much complexity in a single function. You end up sacrificing readability to reduce nesting, instead of actually addressing the issue and splitting the logic.

Thread Thread
joelbonetr profile image
JoelBonetR

If you use a conditional return at the beginning of your function you can prevent everything else to execute, useEffects, useStates, whatever custom function and so on so this pattern is very used TBH, can't see the issue with it, it's pretty understandable, and useful in tones of different architectures. 🤷🏻‍♀️

Thread Thread
lukeshiru profile image
Luke Shiru • Edited on

That's my point when I say that needing an early return is a sign that you actually need to simplify that function. Maybe all those hooks should be in another place, like a custom hook or another component (which most definitely would help readability more than putting returns all over the place).

Thread Thread
joelbonetr profile image
JoelBonetR • Edited on

You'll need to USE this custom hook anyway inside your component, isn't it?

Those are two different things, you can simplify as much as you can the functions, apply SOLID into them and extract functions from components, but a component itself will probably need any hook (being custom or not) and some presentation logic.

It's common to use this pattern in Next JS, specially when you use SSR to avoid client-server missalignments:

if( !someProp ) return null;
Enter fullscreen mode Exit fullscreen mode

While it's not so common in React, is also perfectly valid as defensive programming technique when a prop is required for a component to render properly.
It's placed at the beginning of the component, pretty understandable and suits any case in which a default prop value is not beneficial or, if you've preference for other patterns, we can say it's beneficial whenever a ternary would be worse.

Also consider that:

function Test({ userName }) {
  return userName && (<p>hi {userName}!</p>);
}
Enter fullscreen mode Exit fullscreen mode

Using this pattern (or similar ones) we receive undefined as return value whenever Test component either doesn't receive a prop or the prop evaluates to falsy.

So if you do something like:

/**
 * Returns a message depending on the quest result
 * @param {boolean} winner
 */
function QuestResult({ winner }) {
  return winner && (<p>You {winner ? 'WIN' : 'LOSE'}!</p>);
}
Enter fullscreen mode Exit fullscreen mode
export default function Whatever() {
  return (
    <div className="results">
      <h1>Quest Finished</h1>
      <h2>Result</h2>
      <QuestResult winner={false} />
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

You'll get no message if you lose because winner is false, so it can cause non desired side effects.
So it's better to stablish that pattern as default one (from my experience):

/**
 * Returns a message depending on the quest result
 * @param {boolean} winner
 */
function QuestResult({ winner }) {
  if( typeof winner !== 'boolean' ) return null;
  return <p>You {winner ? 'WIN' : 'LOSE'}!</p>;
}
Enter fullscreen mode Exit fullscreen mode

Of course you can do the same condition with a ternary:

/**
 * Returns a message depending on the quest result
 * @param {boolean} winner
 */
function QuestResult({ winner }) {
    return typeof winner !== 'boolean' ? <p>You {winner ? 'WIN' : 'LOSE'}!</p> : null;
}
Enter fullscreen mode Exit fullscreen mode

but some components grow inevitably so they will become less readable plus this way you can control the condition easily and not having it coupled to the main return of the component. Easier to spot in PRs also!
Just look at this super simple example, we get a nested ternary here.
Is it worthy to decouple the message on a function getResultMessage(winner) or is better to use the other pattern?
And we even considered the hooks in the example above.

export default function MyComponent(props) {
  if( !props ) return null;
  // effects, states, whatever
  return <Whatever props={props} />
}
Enter fullscreen mode Exit fullscreen mode

In this case nothing will be executed if props is not set (or falsy)

export default function MyComponent(props) {
  // effects, states, whatever
  return  props ? <Whatever props={props} /> : null;
}
Enter fullscreen mode Exit fullscreen mode

In this one they will be (What a waste, huh?)

Thread Thread
lukeshiru profile image
Luke Shiru

It's common to use this pattern in Next JS, specially when you use SSR to avoid client-server missalignments.

If you do:

if (!someProp) return null;

useHooks();

return <Example someProp={someProp} />;
Enter fullscreen mode Exit fullscreen mode

It's the same as doing:

if (!someProp) {
    return null;
} else {
    useHooks();

    return <Example someProp={someProp} />;
}
Enter fullscreen mode Exit fullscreen mode

Both have the problem that you're optionally calling hooks, so both are going against the rules of hooks. So in either case you need to call hooks first and then return, so the actual "versus" is:

useHooks();

if (!someProp) return null;
return <Example someProp={someProp} />;

// vs

useHooks();

if (!someProp) {
    return null;
} else {
    return <Example someProp={someProp} />;
}

// or ...

useHooks();

return someProp : <Example someProp={someProp} /> : null;
Enter fullscreen mode Exit fullscreen mode

So in the case of hooks, the early return is not helping at all, is pretty much the same, just with a different style (which I stated before, I like less than just using a ternary).

While it's not so common in React, it is also perfectly valid as defensive programming technique when a prop is required for a component to render properly.

I was talking about "defensive programming" when I said that you should take that as a sign something should be worked on. If you need to avoid passing something because it could break stuff, then maybe make that stuff more stable? The previous example could avoid the "if" altogether if the Example component was able to receive someProp optionally, but because is required we had to write all that "defensive" code.

Using this pattern (or similar ones) we receive undefined as return value whenever Test component either doesn't receive a prop or the prop evaluates to falsy.

I've already said it in several comments, but I'm not in favor of short-circuiting (not just in JSX, but anywhere). It's hacky code and it should be avoided. A ternary is my default solution for code like that, but also I use default values or nullish coalescing when needed:

const Test = ({ username = "Guest" }) => <p>Hi, {username}!</p>;
// or
const Test = ({ username }) => <p>Hi, {username ?? "Guest"}!</p>;
Enter fullscreen mode Exit fullscreen mode

Also that QuestResult component has a short circuit just because of reasons, it should be written like this:

/**
 * Returns a message depending on the quest result
 *
 * @type {import("react").FC<{ winner?: boolean }>}
 */
const QuestResult = ({ winner = false }) => (
    <p>You {winner ? "WIN" : "LOSE"}!</p>
);
Enter fullscreen mode Exit fullscreen mode

So you don't need to do an early return there, neither you need the nested ternary. As I said, when you think: "Hum! I could use an early return here", that generally means you need to fix something else. You might argue "but, my function is rendering that p depending on if winner was passed as a boolean or not", and my argument would be: If that is optionally rendered, then you should have other property for that (like hidden or visible) so that you don't have two unrelated pieces of logic (showing the message, and the content of the said message) coming from the same prop.

Your last example I addressed at the beginning of this comment, but with either approach, you should always run effects, so early return doesn't solve much (it might even potentially cause a bug).

Early return are almost always presented as a really "cool hack", but is only one style for doing things that, at least from my point of view, only makes the flow of the function less readable with no real benefits.

Thread Thread
danwalsh profile image
Dan Walsh

Really good points you bring up.

Just on one of them:

I was talking about "defensive programming" when I said that you should take that as a sign something should be worked on. If you need to avoid passing something because it could break stuff, then maybe make that stuff more stable? The previous example could avoid the "if" altogether if the Example component was able to receive someProp optionally, but because is required we had to write all that "defensive" code.

In most of the projects I work on, I need to do a lot of “progressive enhancement” on more monolithic systems (which inherently come with a number of restrictions/limitations/requirements). I’m often having to server-side render component data as Objects on the window global and then ingest them when my components conditionally render. Because I can never guarantee the stability of that data, I sometimes (not all the time) need to rely on the early return pattern to ensure the stability of the component.

Sometimes it’s because a CMS author has used a few unescaped characters and broken the Object (which we always do our best to sanitise, regardless). Other times a regression issue might cause the data Object to be malformed when it renders. But due to the nature of the environment, there is sometimes no way to make the data source “bullet proof”.

In my experience, when you can’t guarantee the existence and stability of your props, the early return pattern helps to maintain the stability of your components.

Thread Thread
lukeshiru profile image
Luke Shiru

Oh yup, at work we have to deal with some unstable APIs quite often. We usually have types that reflect that (pretty much everything is Partial because it could be there or not), and make great use of optional chaining and nullish coalescing. The other tools that are great for flaky data sources are io-ts and zod, both provide a safe layer on top of data sources that is great to work with with JS and TS.

I'm not saying "defensive programming" is always bad. My point was mainly that, from my experience at least, more often than not folks default to do an early return when the issue could be solved in a better way.

Thread Thread
danwalsh profile image
Dan Walsh

Cheers for those library links! I haven't used them before, but they look really intriguing.

Agree that often you see the "right now" solution instead of the "right" solution (and I mean "'right' solution" very loosely, in that there is no one way to skin a cat).

Sometimes the competing budget, timeline, and plethora of other nagging responsibilities prevents us from taking the time think through these logical issues and refactor with leaner, more readable code, for sure. On the other hand, while some might find an early return more verbose, requiring more concentration to read, I feel they can still be as robust as any other logic that performs a similar function.

How great that all of this good discussion on programming patterns has spiralled out from a post on conditionally rendering JSX! 😄

Thread Thread
joelbonetr profile image
JoelBonetR

Adding that it depends on the architecture of the frontend in this case.
When I do a "standard React SPA" I barely use this early return, but having Next JS with SSR and a headless CMS as source of structure/data makes it almost mandatory. In this last case there's a builder which receives a big JSON from a micro which defines which components will show up on a given view through a dynamic component loader process.

We cannot ensure the structure and/or content inside the CMS to be reliable as it's human made, and during those months it has been proved that human errors could appear.

I agree on that

Both have the problem that you're optionally calling hooks, so both are going against the rules of hooks.

generally speaking, but not in this context.
As it's Server Side Rendered, it will not magically get the data afterwards through an async process or whatever. The structure and data you receive into the JS is the "director" about what and how will be shown, and what you actually handle in the view is the pre-rendered in which you can safely use this early return to avoid further execution of that piece of software.

you can use a Node API and/or handle requests to third parties or other micros in the server context (getServerSideProps) but you can need, eventually, to add an async call to get data from a micro or third party to search or filter.
Then you have two options, either reload the view adding query params or whatever, handling it in the Node JS context to keep it full-SSRed, or do the async thingy (fetch) in the frontend, in which case I'd recommend a loader/spinner, then the conditional render will look like that:

return loading ? <Loader /> : <DataTable data={fetchedData} />
Enter fullscreen mode Exit fullscreen mode

and you'll never return null nor undefined because there's no sense on it.

Collapse
miketalbot profile image
Mike Talbot • Edited on

Or even:

    const MyComponent = ({name})=>!!name && 
         <p>Hi! My name is {name}.</p>;
Enter fullscreen mode Exit fullscreen mode

Though I definitely think ternaries are easier to comprehend if you aren't used to looking at that kind of logic

Thread Thread
moopet profile image
Ben Sinclair

Cramming everything you possibly can on to one line is definitely something I see a lot in Javascript, but I think it's a weird and ultimately self-destructive style.

There's no penaltly in terms of performance to use a little vertical space, and I much prefer comfortable reading instead of horizontal scrollbars or weird line-wrapping.

Thread Thread
Sloan, the sloth mascot
Comment deleted
lukeshiru profile image
Luke Shiru

The idea isn't to put everything in a single line, the idea is to not use return as a "break" or "exit". If you need to exit early to make your code more readable, that means your code might need to refactored and simplified.

Collapse
rasaf_ibrahim profile image
Rasaf Ibrahim Author

Thank you for writing about Guard Clause in details. I didn't know about this. I have modified the article and added this example under Logical Operator section as Guard Clause has ! (NOT Logical Operator).

Collapse
danwalsh profile image
Dan Walsh

Cheers, mate. But just to be clear, a guard clause doesn’t specifically use a NOT operator. It can be any sort of expression that, when evaluated to be false (or falsy, depending on your logic), returns the function early.

Thread Thread
rasaf_ibrahim profile image
Rasaf Ibrahim Author

Very useful information, thank you. 😃

Collapse
k1dv5 profile image
Kidus Adugna

Why not just return instead of return null?

Collapse
danwalsh profile image
Dan Walsh

If I remember correctly, return on its own infers a return type of void, whereas return null is an acceptable React.ReactNode return type, as far as TypeScript is concerned.

Thread Thread
fjones profile image
FJones

And void in turn results in undefined on the caller, which React now supports, but I would still discourage. The reason support for it was added was, in part, inconsistency between nested and root-level conditional rendering.

Collapse
rasaf_ibrahim profile image
Rasaf Ibrahim Author

Yes, you can definitely do that as we know whenever JavaScript sees the return keyword, it immediately exits the function.

Collapse
miketalbot profile image
Mike Talbot

It's not rendering <div>s it's using Fragments.

Collapse
danwalsh profile image
Dan Walsh • Edited on

Correct—I meant that more broadly regarding returning null, not pointing to any specific examples.

Collapse
horhorou profile image
horhorou

For my part, in all my projects, whether personal or professional, I create an If component with a condition as property

It allows me to have something easier to read in my code


type Props = {
 children: ReactNode
 condition : boolean
}

 const IfComponent : FunctionComponent<Props> = ({ condition, children })=>{

   if(!!condition)
     return children

   return <></>
}
Enter fullscreen mode Exit fullscreen mode
Collapse
brense profile image
Rense Bakker • Edited on

This is more or less my preferred way as well. However it is good to note that the component you pass as children will still be mounted (but not rendered) even if the condition is false. The only way to avoid the component being mounted is to have the condition and the component initialization in the same place.

function AlwaysMounted({condition, children}:React.PropsWithChildren<{condition:boolean}>){
  return !!condition ? children : null
}

const myCondition = false

// MyComponent will always be mounted (but not rendered)
return <AlwaysMounted condition={myCondition}><MyComponent /></AlwaysMounted>

// This is the only way to not mount your component if the condition is false
return !!myCondition ? <MyComponent /> : null
Enter fullscreen mode Exit fullscreen mode
Collapse
moopet profile image
Ben Sinclair

Won't all of these render a div regardless, though?

Collapse
rasaf_ibrahim profile image
Rasaf Ibrahim Author

Here, I am rendering short text (<p> tag) in the conditions to make the example short. But you are not limited to any specific html tag, you can render any html tag, even you can render another component.

Collapse
miketalbot profile image
Mike Talbot

Fragments don't render divs, they are a placeholder that renders nothing at all to the DOM, so the only thing rendered is what is returned by the functions etc.

Collapse
moopet profile image
Ben Sinclair

So all these examples, which return a wrapper div with conditional content - does React strip out the empty div automatically?

Thread Thread
miketalbot profile image
Mike Talbot • Edited on

<></> is a Fragment not a <div></div>, so nothing apart from the content is rendered.

Thread Thread
moopet profile image
Ben Sinclair

Ah, OP has updated the post. It used to use <div> in all the examples.

Thread Thread
miketalbot profile image
Mike Talbot

Ahhh!!! That explains a lot :)

Collapse
716green profile image
Bob Bass

I never thought about using an IIFE for if/else and switch statements. That's pretty neat.