【问题标题】:How can I dynamically load an icon using its snake_case name (React, material-ui)如何使用它的snake_case名称动态加载图标(React,material-ui)
【发布时间】:2019-10-15 14:09:32
【问题描述】:

通常我会通过直接导入 per the material-ui instructions 来使用 material-ui 图标。

但我有一个文本标签,它是实际的图标名称(如calendar_view_day),需要从中动态获取和呈现图标组件。

我该怎么做:

render() {
  return (
    <Icon name="calendar_view_day" color="primary" />
  )
}

代替:

render() {
  return (
    <CalendarViewDay color="primary" />  // Imported by name
  )
}

【问题讨论】:

    标签: reactjs icons material-design material-ui


    【解决方案1】:

    好吧,所以我想太多了。

    正确答案

    原来material-ui 包含一个图标组件,可让您执行此操作……它会自行转换名称,因此接受蛇、帕斯卡和其他变体。 注意,正如 cmets 中所指出的,这将大大增加捆绑包的大小。如果您受到捆绑包大小的限制,则必须采用不同的方法从某个地方提供图标 SVG!

    import Icon from '@material-ui/core/Icon'
    
    ...
    
    render() {
      return (
        <Icon>{props.iconName}</Icon>
      )
    }
    

    上一个答案(工作但大量矫枉过正)

    创建函数到:

    ...然后使用material-ui图标组件。

    代码如下:

    import Icon from '@material-ui/core/Icon'
    
    function upperFirst(string) {
      return string.slice(0, 1).toUpperCase() + string.slice(1, string.length)
    }
    
    function fixIconNames(string) {
      const name = string.split('_').map(upperFirst).join('')
      if (name === '3dRotation') {
        return 'ThreeDRotation'
      } else if (name === '4k') {
        return 'FourK'
      } else if (name === '360') {
        return 'ThreeSixty'
      }
      return name
    }
    
    ...
    
    render() {
      const iconName = fixIconNames(props.iconName)
      return (
        <Icon>{props.iconName}</Icon>
      )
    }
    

    【讨论】:

    • material-ui 导入整个 Icon 模块将解决该功能,但会爆炸包!您可以通过React official guideline 分析包大小
    • 感谢@Navid,在我的回答中添加了健康警告。
    • 此解决方案使用字体图标而不是 svg 图标。需要加载使用的字体。见:material-ui.com/components/icons/#icon-font-icons
    • “正确答案”只为我打印字符串 props.iconName,不显示实际图标。
    • @jonasRosenvist,您还需要在代码中包含一些链接:fonts.googleapis.com/icon?family=Material+Icons" />
    【解决方案2】:

    正如上面对 thclark 回答的 cmets 所述,使用 Icon 组件的解决方案将使用 Material-UI 图标的字体版本,其中不包含完整的图标集.

    通过使用相同的方法来获得正确的图标名称(从 thclark 借用)结合 React.createElement 可以解决问题。我在 TypeScript 中做到了这一点,在 vanilla javascript 中更容易。这里是 TS 版本的组件(dynamicIcon.tsx),也可以在this repo 中找到:

    import * as React from 'react';
    import * as Icons from '@material-ui/icons/';
    
    type IconType = typeof import('@material-ui/icons/index');
    
    interface DynamicIconProps {
        iconName: string,
        className: string
    }
    
    function upperFirst(string:string) {
        return string.slice(0, 1).toUpperCase() + string.slice(1, string.length)
    }
      
    function fixIconNames(string:string) {
        const name = string.split('-').map(upperFirst).join('')
        if (name === '3dRotation') {
            return 'ThreeDRotation'
        } else if (name === '4k') {
            return 'FourK'
        } else if (name === '360') {
            return 'ThreeSixty'
        }
        return name;
    }
    
    export default class DynamicIcon extends React.Component<DynamicIconProps> {
        constructor(props: DynamicIconProps) {
            super(props);
        }
    
        render() {
            return React.createElement(Icons[fixIconNames(this.props.iconName)! as keyof IconType], {className: this.props.className});
        }
    }
    

    【讨论】:

    • 提供 TS 解决方案做得很好。但是元素的创建从来都不是问题——它是包的大小。我不使用 TS,但据我所知,为了工作,这仍然必须将每个图标导入到包中(检查create-react-app.dev/docs/analyzing-the-bundle-size)。
    猜你喜欢
    • 2023-03-04
    • 2019-02-04
    • 2021-03-22
    • 1970-01-01
    • 2016-04-02
    • 2018-01-07
    • 2018-11-22
    • 1970-01-01
    • 2021-07-05
    相关资源
    最近更新 更多