Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Antd icon type from string in v4

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} />.

like image 255
Louis Emard Avatar asked Jun 05 '20 15:06

Louis Emard


People also ask

Which official blocks support antd@4?

All official blocks also support antd@4. Please use it with peace of mind. Due to the deletion of the 4.0 icon, if the icon disappears, please find a suitable replacement in the official website of antd.

How to migrate to the new version of the antd plugin?

If you want to migrate to the new version, you can implement it as described in the above document, but you can set the icon configuration menu icon in Pro, which will not be supported in 4.0, so we provide the corresponding [plugin] (https: / /github.com/umijs/umi-plugin-antd-icon-config) to retain this feature. And set in config.ts

Do I need to install ant-design/icons?

You'll need to install ant-design/icons if you haven't already: Since reason performance on the previous version, antd team was apply tree-shaking to use icon.

Should I install and upgrade antd@4 for the first time?

For a person who loves early adopters, of course, he must install and upgrade the first time. After consulting the bean paste teacher and getting a promise that the api will not be modified, I have completed the migration in my project. Enjoy the advantages of antd@4 for the first time.


5 Answers

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'} />
like image 173
Rikesh Lal Shrestha Avatar answered Nov 08 '22 23:11

Rikesh Lal Shrestha


That seems to work

const Icon = ({type, ...rest}) => {
  const icons = require(`@ant-design/icons`);
  const Component = icons[type];
  return <Component {...rest}/>
}
like image 26
Józef Podlecki Avatar answered Nov 08 '22 22:11

Józef Podlecki


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;
  • Usage
<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>
like image 39
doctorgu Avatar answered Nov 09 '22 00:11

doctorgu


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 />
like image 20
CeamKrier Avatar answered Nov 09 '22 00:11

CeamKrier


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

like image 45
Mohamed Aarab Avatar answered Nov 08 '22 23:11

Mohamed Aarab