React, how to dynamically choose a component to render

I had the need to render a list of items in a menu, each with its own icon.

I initially hardcoded the component in a menu, like this:

const menu = [
  {
    title: 'Home',
    icon: <HomeIcon className="mr-3 ml-1 h-5 w-5" /> 
  },
  { title: 'Notifications', icon: <BellIcon className="mr-3 ml-1 h-5 w-5" /> },
  { title: 'Profile', icon: <UserIcon className="mr-3 ml-1 h-5 w-5" /> },
]

using the very cool @heroicons/react package.

In the JSX I iterated on the menu array to show {item.icon}

But then I had to change the Tailwind classes I was using depending on the responsive state of the app, for which I used the react-responsive package.

I decided to pass a string instead, so I first did this:

const menu = [
  { title: 'Home', icon: 'HomeIcon' },
  { title: 'Notifications', icon: 'BellIcon' },
  { title: 'Profile', icon: 'UserIcon' },
]

const Icon = (props) => {
  const { name } = props

  let icon = null
  if (name === 'HomeIcon') icon = HomeIcon
  if (name === 'BellIcon') icon = BellIcon
  if (name === 'UserIcon') icon = UserIcon

  return React.createElement(icon, { ...props })
}

...

<Icon name={item.icon} />

Another possible solution would be to use an object to look up the components, instead of a bunch of if checks:

const icons = {
  HomeIcon,
  BellIcon,
  UserIcon,
}

const Icon = (props) => {
  const { name } = props

  const TheIcon = icons[name]
  return <TheIcon {...props} />
}

<Icon name={item.icon} />

I had to use TheIcon as React components start with an uppercase letter by convention.

This was good enough, but I then realized I could do it in a much simpler way by using the actual component instead of a string in the menu array:

const menu = [
  { title: 'Home', icon: HomeIcon },
  { title: 'Notifications', icon: BellIcon },
  { title: 'Profile', icon: UserIcon },
]

const Icon = (props) => {
  const { icon } = props
  const TheIcon = icon
  return <TheIcon {...props} />
}

...

<Icon icon={item.icon} />

Download my free React Handbook and check out my React Masterclass!

⭐️ Join the waiting list for the JavaScript Masterclass ⭐️