You cannot use if-else statements inside JSX. If you want to check conditions inside JSX, use the ternary operator or put the conditional logic into a function and call that function from JSX.
React follows a declarative programming style. React compiles regular JSX expressions to regular JavaScript function calls. According to Official React docs, JSX just provides syntactic sugar. Let's take a look at the below JSX.
The message is a simple component. The Alert resides inside the Message component.
import { ReactNode } from "react";
import { Alert } from "react-bootstrap";
interface ButtonProps {
props: StyleProps,
children: ReactNode
}
interface StyleProps {
variant: string,
}
const Message = ({props, children}: ButtonProps) =>{
return(
<div>
<Alert variant={props.variant}>
{children}
</Alert>
</div>
)
}
export default Message
Listed below is the general usage of the Message component.
<Message props={{variant: "success"}}>
Great Job!
</Message>
React translates this JSX to
React.createElement(Message, {
props: {
variant: "success"
}
}, "Great Job!")
Then we have the Alert JSX in the Message component. React does another translation.
React.createElement(Alert, {
variant: props.variant
}, children)
When you take the Message component as a whole, the React translation looks like
React.createElement(Message, {
props: {
variant: "success"
}
},React.createElement(Alert, {
variant: props.variant
}, children))
JSX expressions must have one parent element
As you can see, the result is a nested element. React starts from the top most parent JSX and nests all the JSX expressions as elements. The result is a deeply nested statement of React.createElements. That is the reason for the "JSX expressions must have one parent element" error when you don't wrap your JSX elements in a parent element. React doesn't know where to find the parent element to create the nested elements.
If-else in JSX elements
If you take a closer look at the resulted element, you will see there is no place for if-else statements. Therefore, we have two options when it comes to if-else inside JSX.
- Use ternary expressions,/li>
- Call a function from JSX
Using ternary expressions in JSX
Using ternary expressions in JSX works out great for simple if-else statements. When it comes to nested or complex if-else statements, deligating that logic to a function makes more sense.
{
score === 100 ?
<Message props={{variant: "success"}}>Great Job!</Message>
:
<Message props={{variant: "info"}}>Good Job!</Message>
}
Call a function from JSX expression
Suitable for complex and lengthy if-else statements. The below code demonstrates how to use a function call to display a JSX element conditionally.
import { useState } from "react";
import Message from "./components/Message";
export const App = () => {
const [score, setScore] = useState(0)
const displayMessage = () => {
if(score === 80){
return <Message props={{variant: "info"}}>You have passed the test!</Message>
}
else
if(score === 90){
return <Message props={{variant: "primary"}}>Good Job! You have passed the test!</Message>
}
else
if(score === 100){
return <Message props={{variant: "success"}}>Great Job! You Nailed it!</Message>
}
return <Message props={{variant: "warning"}}>Please enter your score</Message>
}
return(
<div style={{width:240}}>
<div style={{padding:10}}>
<label>Your Score: </label>
<select name="select" onChange={(e) => setScore(+(e.target.value))}>
<option value="0"></option>
<option value="80">80</option>
<option value="90">90</option>
<option value="100">100</option>
</select>
</div>
<div style={{padding:10}}>
{displayMessage()}
</div>
</div>
)
}
export default App;
Message Component
import { ReactNode } from "react";
import { Alert } from "react-bootstrap";
interface ButtonProps {
props: StyleProps,
children: ReactNode
}
interface StyleProps {
variant: string,
}
const Message = ({props, children}: ButtonProps) =>{
return(
<div>
<Alert variant={props.variant}>
{children}
</Alert>
</div>
)
}
export default Message