Understanding the "Element" React Component: A Flexible Approach to Conditional Rendering
Tags: webdev, javascript, react, typescript
Published: 2024-01-14 13:55:53

When working with React, developers often encounter scenarios where they need to conditionally render elements based on certain conditions. The provided `Element` component aims to simplify this process by introducing a flexible and intuitive approach to conditional rendering.

## The Problem

When working with React, developers often encounter scenarios where they need to conditionally render elements based on certain conditions. For example, a developer may want to render a button only if a user is logged in. Or, a developer may want to render a form only if a user is logged out.

In these scenarios, developers often use conditional rendering strategies such as the `&&` operator or the ternary operator. While these strategies are effective, they can be difficult to read and maintain. For example, the following code snippet uses the `&&` operator to conditionally render a button:

```tsx
import React from 'react';

export default function Usage() {
  const isLoggedIn = true;

  return (
    <div>
      {/* ✅ Button will be rendered if isLoggedIn is true */}
      {isLoggedIn && <button>Logout</button>}
    </div>
  );
}
```

While this approach is effective, it can be difficult to read and maintain. For example, the following code snippet uses the ternary operator to conditionally render a form:

```tsx
import React from 'react';

export default function Usage() {
  const isLoggedIn = true;

  return (
    <div>
      {/* ✅ Form will be rendered if isLoggedIn is true */}
      {isLoggedIn ? (
        <form>
          <input type="text" />
          <input type="password" />
          <button>Login</button>
        </form>
      ) : null}
    </div>
  );
}
```

The `Element` component aims to simplify this process by introducing a flexible and intuitive approach to conditional rendering. It leverages TypeScript to provide a type-safe interface and improve code clarity.

## Overview - Element Component

The `Element` component is a React component that allows developers to conditionally render elements based on specific conditions. It leverages TypeScript to provide a type-safe interface and improve code clarity.

```tsx
import React, { ComponentProps } from 'react';

type ElementBaseProps<T extends keyof HTMLElementTagNameMap> =
  | {
      as: T;
      /**
       * If `true`, the element will be rendered. If `false`, the element will not be rendered.
       */
      rcIf?: boolean;
      /**
       * If has `rcIf` you can't use `rcElse`.
       */
      rcElse?: never;
    }
  | {
      as: T;
      /**
       * If has `rcElse` you can't use `rcIf`.
       */
      rcIf?: never;
      /**
       * If `true`, the element will not be rendered. If `false`, the element will be rendered.
       */
      rcElse?: boolean;
    };

type ElementProps<T extends keyof HTMLElementTagNameMap> = ElementBaseProps<T> &
  ComponentProps<T>;

export function Element<T extends keyof HTMLElementTagNameMap>({
  as,
  children,
  rcIf = true,
  rcElse = false,
  ...props
}: ElementProps<T>) {
  if (rcIf === false || rcElse === true) {
    return null;
  }

  return React.createElement(as, props as ComponentProps<T>, children);
}

export default Element;
```

## Element Props

The `Element` component accepts the following props:

- `as`: The HTML tag name of the element to be rendered.

- `rcIf`: If `true`, the element will be rendered. If `false`, the element will not be rendered. If `rcElse` is provided, `rcIf` cannot be used, and vice versa.

- `rcElse`: If `true`, the element will not be rendered. If `false`, the element will be rendered. If `rcIf` is provided, `rcElse` cannot be used, and vice versa.

- `children`: The children of the element. This can be a `string`, `a React element`, or `an Array of React elements`.

## Element Usage

The `Element` component can be used to conditionally render elements based on specific conditions. It can be used in the following ways:

```tsx
import React from 'react';
import Element from './Element';

export default function Usage() {
  return (
    <Element as="main">
      {/* ✅ Element Component as a with all props */}
      <Element as="a" href="https://www.google.com" target="_blank">
        Google
      </Element>
      {/* ✅ Element Component as h1 with all props */}
      <Element rcIf as="h1">
        Hello, World!
      </Element>
      {/* ✅ Element Component as section with all props */}
      <Element as="section" rcIf={false}>
        Hello, World!
      </Element>
      {/* ✅ Element Component as span with all props */}
      <Element rcElse as="span">
        Hello, World!
      </Element>
      {/* ❌ You can't use rcIf and rcElse together */}
      <Element rcIf as="h4" rcElse={false}>
        Hello, World!
      </Element>
      {/* ✅ Element Component as Input */}
      <Element as="input" type="color" />
      <Element as="input" type="date" />
      <Element as="input" type="datetime-local" />
      <Element as="input" type="email" />
      <Element as="input" type="file" />
      <Element as="input" type="month" />
      <Element as="input" type="number" />
      <Element as="input" type="password" />
      <Element as="input" type="radio" />
      <Element as="input" type="range" />
      <Element as="input" type="search" />
      <Element as="input" type="tel" />
      <Element as="input" type="text" />

      {/* ✅ Element Component as div with inline style */}
      <Element
        as="div"
        style={{
          display: 'flex',
          flexDirection: 'column',
          gap: '10px',
          height: '30vh',
          overflowY: 'auto',
        }}
      >
        {todos.map((todo) => {
          return (
            <Element as="div" key={todo.id}>
              <Element as="input" checked={todo.completed} type="checkbox" />
              <Element as="h2">{todo.title}</Element>
              <Element as="p">
                {todo.completed ? 'Completed' : 'Not completed'}
              </Element>
            </Element>
          );
        })}
      </Element>
    </Element>
  );
}
```

## Features

- `Type Safety`: The `Element` component is built with TypeScript, which allows it to provide a type-safe interface. This helps reduce the risk of unexpected bugs and improves code clarity.

- `Ease of Use`: The `Element` component is easy to use. It provides a straightforward API that allows developers to conditionally render elements based on specific conditions.

- `Flexibility`: The `Element` component is flexible. It can be used to render elements based on a single condition or multiple conditions.

- `Exclusive Usage`: If `rcIf` is provided, `rcElse` cannot be used, and vice versa. This ensures that only one conditional rendering strategy is employed for each instance of the `Element` component.

## Drawing Inspiration from Angular and Vue

_The conditional rendering approach implemented in the `Element` component draws inspiration from similar concepts in Angular and Vue. Angular developers are familiar with the `*ngIf` directive, while Vue developers often use the `v-if` and `v-else` directives. The `Element` component adopts a similar philosophy, providing a concise and readable way to conditionally render elements in React._

## Conclusion

The `Element` component is a React component that allows developers to conditionally render elements based on specific conditions. It leverages TypeScript to provide a type-safe interface and improve code clarity.

Feel free to incorporate the `Element` component into your React projects to simplify conditional rendering and improve the overall maintainability of your codebase.

Thanks for reading! Happy coding!