Reputation: 171
I have to upgrade antd from v3 to v4, previously we used to show some icons from string passed as prop like this :
<Icon type={props.icon} />
Is there a way to achieve something like this in antd v4 with the new Icon system ? I know the existence of '@ant-design/compatible'
but the migration was made to reduce the bundle size so i'd like to avoid this solution.
Edit : I just changed the way I use icons, in my config file I import the icons and pass them to my generator like this : icon = {props.icon}
instead of the previous <Icon type={props.icon} />
.
Upvotes: 11
Views: 10281
Reputation: 946
With the help of @Cea's approach, I have managed to set Icons dynamically as shown here:
import * as AntdIcons from '@ant-design/icons';
const CustomIcon=(type:string)=>{
const AntdIcon= AntdIcons[type] // not AntdIcons[iconDetails.render] as @Cea mention;
return <AntdIcon/>
}
Then inside my loop menu, I retrieve the Icon name an pass it to the CustomIcon function as a parameter.
I hope this helps someone
Upvotes: 1
Reputation: 1132
I was using the response by @rikesh-lal-shrestha but I need pass additional props, this is my solution based in @doctorgu response
//DynamicIcon.jsx
import {
QuestionOutlined,
DashboardOutlined,
SmileOutlined,
FormOutlined,
TabletOutlined,
ProfileOutlined,
CheckCircleOutlined,
WarningOutlined,
UserOutlined,
HighlightOutlined,
TableOutlined,
CloseCircleOutlined,
} from '@ant-design/icons';
import * as PropTypes from 'prop-types';
const IconSelector = ({ type, ...rest }) => {
const getIcon = (iconType) => ({
QuestionOutlined: <QuestionOutlined {...rest} />,
DashboardOutlined: <DashboardOutlined {...rest} />,
SmileOutlined: <SmileOutlined {...rest} />,
FormOutlined: <FormOutlined {...rest} />,
TabletOutlined: <TabletOutlined {...rest} />,
ProfileOutlined: <ProfileOutlined {...rest} />,
CheckCircleOutlined: <CheckCircleOutlined {...rest} />,
WarningOutlined: <WarningOutlined {...rest} />,
UserOutlined: <UserOutlined {...rest} />,
HighlightOutlined: <HighlightOutlined {...rest} />,
CloseCircleOutlined: <CloseCircleOutlined {...rest} />,
TableOutlined: <TableOutlined {...rest} />,
}[iconType]);
return getIcon(type) || <QuestionOutlined {...rest} />;
};
IconSelector.propTypes = {
type: PropTypes.string,
};
export default IconSelector;
Usage
<DynamicIcon type={icon} style={{ fontSize: 24, color: color || 'red' }} />
Upvotes: 0
Reputation: 839
You also can import all the files from antd/icons as:
import * as AntdIcons from '@ant-design/icons';
Then you can access all the available icons from AntdIcons
variable as follows:
const AntdIcon = AntdIcons[iconDetails.render];
Where iconDetails.render
is a variable that is something like HomeOutlined
, SettingsOutlined
etc..
Then finally, you can render your components as
<AntdIcon />
Upvotes: 4
Reputation: 634
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>
Upvotes: 1
Reputation: 111
I am using @loadable/component and by created a dynamic component that passes type
File DynamicIcon.js:
import loadable from "@loadable/component";
const DynamicIcon = loadable(props =>
import(`@ant-design/icons/es/icons/${props.type}.js`)
.catch(err => import(`@ant-design/icons/es/icons/WarningOutlined.js`)))
export default DynamicIcon;
And invoke the icon as before v3:
<DynamicIcon type={'TagOutlined'} />
Upvotes: 9
Reputation: 11283
const Icon = ({type, ...rest}) => {
const icons = require(`@ant-design/icons`);
const Component = icons[type];
return <Component {...rest}/>
}
Upvotes: 4