I am here to find a way to dynamically load icon for menu. And I don't like other solution. So I decided to create another solution.
My solution is simple. Actually it is not dynamic, it choose already loaded component.
But it is safe for Webpack because it will include only used component in source code. It means result size is smaller than including over 700 count of all svg files in published folder.
// IconSelector.tsx
import React from 'react';
import {
QuestionOutlined,
DashboardOutlined,
SmileOutlined,
FormOutlined,
TabletOutlined,
ProfileOutlined,
CheckCircleOutlined,
WarningOutlined,
UserOutlined,
HighlightOutlined,
TableOutlined,
} from '@ant-design/icons';
interface IconSelectorProps {
type: string;
}
const IconSelector: React.FC<IconSelectorProps> = (props: IconSelectorProps) => {
const Icons = {
QuestionOutlined: <QuestionOutlined />,
DashboardOutlined: <DashboardOutlined />,
SmileOutlined: <SmileOutlined />,
FormOutlined: <FormOutlined />,
TabletOutlined: <TabletOutlined />,
ProfileOutlined: <ProfileOutlined />,
CheckCircleOutlined: <CheckCircleOutlined />,
WarningOutlined: <WarningOutlined />,
UserOutlined: <UserOutlined />,
HighlightOutlined: <HighlightOutlined />,
TableOutlined: <TableOutlined />,
};
const getIcon = (type: string) => {
// Default Icon when not found
let comp = <QuestionOutlined />;
let typeNew = type;
// Default is Outlined when no theme was appended (ex: 'smile')
if (!typeNew.match(/.+(Outlined|Filled|TwoTone)$/i)) {
typeNew += 'Outlined';
}
// If found by key then return value which is component
const found = Object.entries(Icons).find(([k]) => k.toLowerCase() === typeNew.toLowerCase());
if (found) {
[, comp] = found;
}
return comp;
};
return getIcon(props.type);
};
export default IconSelector;
<Menu.Item key="1" icon={menu.icon ? <IconSelector type={menu.icon} /> : null}>
Smile
</Menu>
Or
<Menu.Item key="1">
<IconSelector type="smile" />
<span>Smile</span>
</Menu>