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} />
→ I wrote 17 books to help you become a better developer, download them all at $0 cost by joining my newsletter
→ JOIN MY CODING BOOTCAMP, an amazing cohort course that will be a huge step up in your coding career - covering React, Next.js - next edition February 2025