Recently, I've come across this pattern more frequently and I wanted to share. It's a bit more verbose initially, but is nice on the eyes.
The Typical Approach: Conditional Rendering in JSX
The Traditional Version
Consider this example where a button component could take on one of three styles: primary, secondary, or danger.
interface ButtonProps {
type: 'primary' | 'secondary' | 'danger';
}
const Button: React.FC<ButtonProps> = ({ type }) => {
return (
<>
{type === 'primary' && <button className="btn-primary">Primary</button>}
{type === 'secondary' && <button className="btn-secondary">Secondary</button>}
{type === 'danger' && <button className="btn-danger">Danger</button>}
</>
);
};
Here, we used conditional rendering directly within the JSX. It's not a problem in this small example, but as your component grows, this pattern can create clutter and hamper readability.
A Switch-Case Version
By using a switch-case
statement, we can make the code much more readable:
interface ButtonProps {
type: 'primary' | 'secondary' | 'danger';
}
const Button: React.FC<ButtonProps> = ({ type }) => {
switch (type) {
case 'primary':
return <button className="btn-primary">Primary</button>;
case 'secondary':
return <button className="btn-secondary">Secondary</button>;
default:
return <button className="btn-danger">Danger</button>;
}
};
The Readability Advantage of Using Switch-Case
Easy Scanning
-
Switch-case
statements are visually easier to parse, allowing developers to understand the code faster.
Logical Grouping
- The
case
anddefault
keywords signal distinct branches clearly, unlike conditional rendering where the logic can get lost amidst JSX tags.
Decreased Cognitive Load
- Reading through a
switch-case
statement requires less cognitive effort than tracking multiple conditional operators.
Finally, I want to point out that often the best version is a combination of switch case and conditional statements:
interface ButtonProps {
type: 'primary' | 'secondary' | 'danger';
size: 'small' | 'medium' | 'large';
disabled?: boolean;
}
const Button: React.FC<ButtonProps> = ({ type, size, disabled }) => {
const baseClass = `btn-${type}`;
const sizeClass = `btn-${size}`;
const disabledClass = disabled ? 'btn-disabled' : '';
switch (type) {
case 'primary':
return (
<button className={`${baseClass} ${sizeClass} ${disabledClass}`}>
Primary
</button>
);
case 'secondary':
return (
<button className={`${baseClass} ${sizeClass} ${disabledClass}`}>
Secondary
</button>
);
case 'danger':
return (
<button className={`${baseClass} ${sizeClass} ${disabledClass}`}>
Danger
</button>
);
default:
return <button className="btn-default">Default</button>;
}
};
In my personal opinion, this is far more readable than just conditional statements alone which often become difficult to digest when they are nested more than one level deep.
This is just another tool for the toolbelt. Use it as you find useful. That is all.
Top comments (1)
Nice! Yeah, although perhaps a bit more verbose, the vertical alignment of conditions and templates is easier to scan with your eyes.