Build great React components

February 9, 2021 ∙∙∙ views 3 min read

I'll explain one of the best ways (in my opinion) to keep your React components clean and reusable. I'll be using TypeScript for this and we'll start with a simple Button component:

type Props = {
  children: string
}

function Button({ children }: Props): JSX.Element {
  return (
    <button>
      {children}
    </button>
  )
}

export default Button

Now we want to add a property to this button called size, that's as easy as:

type Props = {
  children: string
  size?: string
}

function Button({ children, size }: Props): JSX.Element {
  // ...

If you're wondering why `size?` has a `?` and `children` doesn't, it means that `size` is an optional property.

Alright, to use this component we can do:

<Button size="md">
  Buy now!
</Button>

That's totally fine and it should work just fine. Although I'm assuming we'll be using this component a lot through our app. Plus, the value of size that we can pass through it'll not be just md right?

This starts to get a little confusing once you start using Button over and over again.


Enums

One way of dealing with the available sizes for our button is by using enums, lets assume our button can have the following sizes: sm, md, lg and xl.

In our Button component we can create an enum to list those:

enum Sizes {
  SM = 'sm',
  MD = 'md',
  LG = 'lg',
  XL = 'xl',
}

type Props = {
  children: string
  // We can also say that from now on the property
  // `size` needs to be one of `Sizes`
  size?: Sizes
}

function Button({ children, size }: Props): JSX.Element {
  // ...

What's good about using an enum? We can export it so it can be used all across your application:

export enum Sizes {
  SM = 'sm',
  MD = 'md',
  LG = 'lg',
  XL = 'xl',
}

When importing and using our button we would do this:

import Button, { Sizes } from '@components/Button'

// ...

<Button size={Sizes.MD}>
  Buy now!
</Button>

So, if for some reason the value of Sizes.[SM | MD | LG | XL] changes you only need to care about changing the logic in your Button component, not on every iteration of Button across the application. This of course can be used for whatever prop you feel it makes sense to use enums.

Another example can be the button type:

export enum Types {
  PRIMARY = 'primary',
  SECONDARY = 'secondary',
  DANGER = 'danger',
}

And using it:

import Button, { Sizes, Types } from '@components/Button'

// ...

<Button type={Types.PRIMARY} size={Sizes.MD}>
  Buy now!
</Button>

That's it. Follow me on Twitter ✌🏻