Improved JSX Readability with Switch-Case Statements in React Components
Tags: typescript, readability, javascript
Published: 2023-09-08 00:17:07


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.

```typescript
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:

```typescript
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` and `default` 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:

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