DEV Community

Cover image for 4 Ways to Render JSX Conditionally in React

4 Ways to Render JSX Conditionally in React

Rasaf Ibrahim on June 24, 2022

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: Ter...
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
 
rasaf_ibrahim profile image
Rasaf Ibrahim

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

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

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

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

Collapse
 
danwalsh profile image
Dan Walsh • Edited

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! ๐Ÿ˜…

Collapse
 
moopet profile image
Ben Sinclair

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

Collapse
 
rasaf_ibrahim profile image
Rasaf Ibrahim

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

<></> 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
 
miketalbot profile image
Mike Talbot โญ • Edited

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.

 
joelbonetr profile image
JoelBonetR ๐Ÿฅ‡ • Edited

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?)

Collapse
 
brense profile image
Rense Bakker • Edited

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
 
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.

 
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. ๐Ÿคท๐Ÿปโ€โ™€๏ธ

Collapse
 
bobdotjs profile image
Bob Bass

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

 
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.