React, динамический выбор компонента для рендеринга
Сегодня хочу разобрать небольшую задачку, которая может кого-то заставить подумать, у меня была необходимость отобразить список элементов в меню, каждый со своей собственной иконкой.
Изначально я сделала глупые элементы для компонента меню, которые выглядели примерно так:
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" /> }, ]
(планировала использовать очень классный пакет @heroicons/react
)
В JSX
я просто прошлась по элементам массива меню, чтобы отрисовать {item.icon}.
Но затем мне пришлось изменить классы Tailwind
, которые я использовала, в зависимости от состояния приложения.
Поэтому я решила передавать строку вместо самой иконки:
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} />
Другим возможным решением было бы использовать объект для поиска компонентов вместо набора проверок:
const icons = { HomeIcon, BellIcon, UserIcon, } const Icon = (props) => { const { name } = props const TheIcon = icons[name] return <TheIcon {...props} /> } <Icon name={item.icon} />
Мне пришлось использовать TheIcon
, поскольку компоненты React
по соглашению начинаются с заглавной буквы.
Это было достаточно хорошо, но затем я поняла, что могу сделать это гораздо более простым способом, используя фактический компонент вместо строки в массиве меню:
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} />
Так, казалось бы, изначально достаточно тривиальная задача, но имеет несколько решений. Думаю, если вы только начинаете разбираться с React, то вам это будет полезно!
Не забывайте подписываться на телеграм канал, чтобы не пропустить новые статьи!