React TypeScript中如何动态添加Material-UI图标?
动态加载Material-UI图标失败的解决方法
问题描述
我有一个带图标的菜单,将其存储在对象数组中,其中图标标签名以Material-UI中的字符串形式保存:
interface MenuButton { text: string, onClickFunction: Function icon: string } export default function Catalog() { ... const generalButtons: MenuButton[] = [ { text: "New Client", onClickFunction: addNewClient, icon: "InfoIcon" }, { text: "New Product", onClickFunction: addNewProduct, icon: "AddShoppingCartIcon" }, { text: "New Gift", onClickFunction: addNewGift, icon: "CardGiftcardIcon" } ] ...
随后我尝试在List组件中使用这些图标,以下是我尝试的最简方案,但出现了问题:
return ( ... <List> {generalButtons.map((button, index) => { const CustomIcon = button.icon return ( <ListItem key={button.text} disablePadding> <ListItemButton onClick={(e) => button.onClickFunction(e)}> <ListItemIcon> <CustomIcon /> </ListItemIcon> <ListItemText primary={button.text} /> </ListItemButton> </ListItem> ) })} </List> )
图标并未显示,反而出现如下错误:
Warning: <InfoIcon /> is using incorrect casing. Use PascalCase for React components, or lowercase for HTML elements.
解决方法
问题核心是你把字符串当作React组件直接渲染了——React无法识别字符串形式的组件名,只会把它当作普通HTML标签处理,因此触发大小写错误。解决思路是先将Material-UI图标组件映射为键值对,再通过字符串键获取对应组件。
1. 导入目标图标组件
先确保你已导入所有用到的Material-UI图标:
import InfoIcon from '@mui/icons-material/Info'; import AddShoppingCartIcon from '@mui/icons-material/AddShoppingCart'; import CardGiftcardIcon from '@mui/icons-material/CardGiftcard';
2. 创建图标映射对象
定义一个对象,将图标名称字符串与对应的组件关联:
const iconMap = { InfoIcon: InfoIcon, AddShoppingCartIcon: AddShoppingCartIcon, CardGiftcardIcon: CardGiftcardIcon };
3. 优化类型定义(可选但推荐)
为了保证TypeScript类型安全,修改MenuButton接口的icon字段类型,限定为iconMap的键:
type IconKey = keyof typeof iconMap; interface MenuButton { text: string; onClickFunction: (e: React.MouseEvent) => void; icon: IconKey; }
4. 渲染时获取正确组件
在map循环中,从iconMap取出对应组件再渲染:
return ( ... <List> {generalButtons.map((button) => { const IconComponent = iconMap[button.icon]; return ( <ListItem key={button.text} disablePadding> <ListItemButton onClick={(e) => button.onClickFunction(e)}> <ListItemIcon> <IconComponent /> </ListItemIcon> <ListItemText primary={button.text} /> </ListItemButton> </ListItem> ) })} </List> )
内容的提问来源于stack exchange,提问作者András Krausz
相关产品推荐
相关产品推荐

