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:
Ternary Operator
Logical Operator
if, else, else if
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
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
)
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
Explanation:
If
labelText
andname
both props are passed into this component, thenlabelText
will be rendered on the screen. But if only one of them (name
orlabelText
) 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
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 asEarly Return
.Early Return
is also calledGuard Clause
orBouncer 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
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
Note:
Have to use an anonymous function (also need to immediately invoke the function )
That's it.😃 Thanks for reading.🎉
Top comments (30)
One more approach you might consider adding to your list is the “guard clause”:
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.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 asGuard Clause
has!
(NOT Logical Operator).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.
Very useful information, thank you. 😃
Why not just
return
instead ofreturn null
?If I remember correctly,
return
on its own infers a return type ofvoid
, whereasreturn null
is an acceptableReact.ReactNode
return type, as far as TypeScript is concerned.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.
Yes, you can definitely do that as we know whenever JavaScript sees the
return
keyword, it immediately exits the function.It's not rendering
<div>
s it's using Fragments.Correct—I meant that more broadly regarding returning
null
, not pointing to any specific examples.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?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" :)
Thanks, @moopet! Complete misread on my behalf! 😅
Won't all of these render a
div
regardless, though?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.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.
So all these examples, which return a wrapper div with conditional content - does React strip out the empty div automatically?
<></>
is a Fragment not a<div></div>
, so nothing apart from the content is rendered.Ah, OP has updated the post. It used to use
<div>
in all the examples.Ahhh!!! That explains a lot :)
Or even:
Though I definitely think ternaries are easier to comprehend if you aren't used to looking at that kind of logic
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.
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:
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:
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:
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):
Of course you can do the same condition with a ternary:
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.
In this case nothing will be executed if props is not set (or falsy)
In this one they will be (What a waste, huh?)
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.
Really good points you bring up.
Just on one of them:
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.
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. 🤷🏻♀️
I never thought about using an IIFE for if/else and switch statements. That's pretty neat.
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! 😄
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
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:
and you'll never return
null
norundefined
because there's no sense on it.