I have the following simple short-circuit statement that should show either a component or nothing:
{profileTypesLoading && <GeneralLoader />}
If the statement is false, it renders a 0
instead of nothing.
I have done a console.log(profileTypesLoading)
just to see quickly what the status of the profileTypesLoading
property is and it's either 1 or 0 as expected. 0 should be false... causing nothing to render. Right?
Any idea why this would happen?
This would solve the problem:
{!!profileTypesLoading && <GeneralLoader />}
As it will convert 0 to false. The reason is when it's 0
the next condition doesn't get executed and it behaves like a number in JavaScript so double negation helps here.
{profileTypesLoading > 0 && <GeneralLoader />}
as the React docs says /// This WILL render component. const xAxis = 100; {xAxis && <YourComponent />} // This WILL NOT render component. const xAxis = 0; {xAxis && <YourComponent />}
Since your condition is falsy and so doesn't return the second argument (<GeneralLoader />
), it will return profileTypesLoading
, which is a number, so react will render it because React skips rendering for anything that is typeof
boolean
or undefined
and will render anything that is typeof
string
or number
:
To make it safe, you can either use a ternary expression {condition ? <Component /> : null}
or boolean cast your condition like {!!condition && <Component />}
Boolean
operator as well if !!condition
confuses you. Something like, { Boolean(condition) && <Component /> }
0 is a falsy value, so when it is evaluated by &&, it returns 0. However, 0 is renderable by React because it is a number:
// Renderable values
1 && <GeneralLoader /> // => Renders <GeneralLoader />
"a string" && <GeneralLoader /> // => Renders <GeneralLoader />
0 && <GeneralLoader /> // => Renders '0'
// Non-renderable values
false && <GeneralLoader /> // => Renders nothing
null && <GeneralLoader /> // => Renders nothing
undefined && <GeneralLoader /> // => Renders nothing
TLDR
This is because of how javascript itself process [truthy and falsy values][1]:
In JavaScript, a truthy value is a value that is considered true when encountered in a Boolean context. All values are truthy unless they are defined as falsy (i.e., except for false, 0, "", null, undefined, and NaN).
When used with the && operator, the returned value depends on the left value:
Examples:
// Truthy values
1 && "hello" // => "hello"
"a string" && "hello" // => "hello"
// Falsy values
0 && "hello" // => 0
false && "hello" // => false
null && "hello" // => null
undefined && "hello" // => undefined
The same rules applies to JSX because it is [a syntax extension to JavaScript][2]. However, the issue is that **
The issue is that 0 is a falsy value, so when it is evaluated by &&, it returns 0. However, 0 is renderable by React because it is a number
// Renderable values
1 && <GeneralLoader /> // => Renders <GeneralLoader />
"a string" && <GeneralLoader /> // => Renders <GeneralLoader />
0 && <GeneralLoader /> // => Renders 0
// Non-renderable values
false && <GeneralLoader /> // => Renders nothing
null && <GeneralLoader /> // => Renders nothing
undefined && <GeneralLoader /> // => Renders nothing
To evaluate a false condition at first, using a const with ternary is a easy way. Example:
On this case a simple button is shown if someCollecctionProperty is empty else, a button with some-options-menu will be shown (Material UI Example)
export default function MyComponent({ obj }) {
const jsxResponse = !obj.someCollecctionProperty.length ? <Button>No Action</Button>
:
<>
<Button
aria-label="more"
aria-controls="long-menu"
aria-haspopup="true"
variant="contained"
onClick={handleClick}
color={'primary'}>
<ThumbUpAltOutlinedIcon/>OK
</Button>
<Menu
id="long-menu"
anchorEl={anchorEl}
keepMounted
open={open}
onClose={handleClose}
>
{obj.someCollecctionProperty.map((option) => (
<MenuItem key={option.id} onClick={handleClose}>
<Avatar variant="square" alt={option.name} src={option.url}/>{option.configName}
</MenuItem>
))}
</Menu>
</>;
return (<div>{jsxResponse}</div>);
}
jsxResponse is the rendered component, 0
on view can be avoid with this
A more straightforward approach:
{Boolean(profileTypesLoading) && <GeneralLoader />}
You can use the double Bang (!!). This returns the boolean true/false association of a value and will not render a 0.
{!!profileTypesLoading && <GeneralLoader/>}
{Boolean(profileTypesLoading) ? :<></>} is also solves the problem.since I am beginner i not sure is has drawback or side effet