DEV Community

Ahmedammarr
Ahmedammarr

Posted on

React Typescript conditional rendering using objects

Lately, I've been looking for a better way to write clean conditional rendering code instead of ternary and && operators and even if statements, because sometimes they can be confusing and I found that I can write the same functionality with objects, it makes the code more readable. let's see how we can write a well-typed object to render a component based on the parent component state and props

export default function Products({state}:ProductsStateEnum)
:ReactElement {
const [_ProductsState, setProductsState] = useState(state)
  const ProductsState: { [key in ProductsStateEnum]: ReactElement } = {
    loading: <Loader width={150} />,
    failed: (
      <div>
          <Badge bg='danger'>Somethig Went Wrong</Badge>
      </div>
    ),
    done: (
      <>
        {products?.map(
          ({ id, title, image, description, category, price }) => (
            <ProductCard
              key={id}
              id={id}
              title={title}
              description={description}
              category={category}
              price={price}
              image={image}
            />
          )
        )}
      </>
    )
  }

  return <div className='row p-3'>{ProductsState[_ProductsState]}</div>
}
Enter fullscreen mode Exit fullscreen mode

We notice here that we didn't write any if statement or any operator, based on the state the component will render the React component with key that's equal to the _ProductsState,

Another and better solution from lukeshiru is using functions/components

import type { FC } from "react";

type State = "loading" | "failed" | "done";
type ProductsProps = { readonly state?: State };

export const Products: FC<ProductsProps> = ({ state = "loading" }) => {
    const ProductsState = (
        {
            loading: () => {/* Your loading code here */},
            failed: () => {/* Your failed code here */},
            done: () => {/* Your done code here */}
        } as Record<State, FC>
    )[state];

    return (
        <div className="row p-3">
            <ProductsState />
        </div>
    );
};
Enter fullscreen mode Exit fullscreen mode

in the above code we can render only the exact state components when needed.

tell me if you know another way to write readable conditional rendering options!

Discussion (3)

Collapse
lukeshiru profile image
LUKESHIRU

Ideally you should have functions/components instead of ReactElements as values of your object, so we only actually render those when needed. With your current approach you're rendering those components even if the state doesn't match, with the following approach we only render them when the state matches:

import type { FC } from "react";

type State = "loading" | "failed" | "done";
type ProductsProps = { readonly state?: State };

export const Products: FC<ProductsProps> = ({ state = "loading" }) => {
    const ProductsState = (
        {
            loading: () => {/* Your loading code here */},
            failed: () => {/* Your failed code here */},
            done: () => {/* Your done code here */}
        } as Record<State, FC>
    )[state];

    return (
        <div className="row p-3">
            <ProductsState />
        </div>
    );
};
Enter fullscreen mode Exit fullscreen mode

Cheers!

Collapse
ahmeddammarr profile image
Ahmedammarr Author

Thank you, your solution is better i'll update the article and use your example and mention your name is that okay with you ?

Collapse
lukeshiru profile image
LUKESHIRU

Sure!