Как я могу динамически загружать значок, используя его имя змеиного случая (React, material-ui)

Обычно я бы использовал значки материалов пользовательского интерфейса, импортировав их напрямую в соответствии с инструкциями Material-UI.

Но у меня есть текстовый тег, который является фактическим именем значка (например, calendar_view_day), и мне нужно динамически получить и отобразить компонент значка из него.

Как я могу что-то вроде:

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

Вместо:

render() {
  return (
    <CalendarViewDay color = "primary" />  // Imported by name
  )
}
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
12
0
14 913
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Итак, я сильно переосмыслил это.

Правильный ответ

Оказывается, material-ui включает в себя компонент значка, который позволяет вам это делать... и сам конвертирует имена, поэтому принимает змею, паскаль и другие варианты. ОСТОРОЖНО, это значительно увеличит размер пакета, как указано в комментариях. Если вы ограничены в размере пакета, вам придется использовать другой подход к обслуживанию значков SVG откуда-то!

import Icon from '@material-ui/core/Icon'

...

render() {
  return (
    <Icon>{props.iconName}</Icon>
  )
}

Предыдущий ответ (работает, но слишком много)

Создайте функцию для:

... Затем используйте компонент Material-UI Icon.

Вот код:

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>
  )
}

импорт всего модуля Значок из материал-пользовательский интерфейс разрешит функциональность, но взорваться станет комплектом! Вы можете проанализировать размер пакета через Официальное руководство React

Navid 24.07.2019 08:53

Спасибо @Navid, добавил к моему ответу предупреждение о вреде для здоровья.

thclark 08.08.2019 18:08

В этом решении используются значки шрифтов вместо значков svg. Требует загрузки используемого шрифта. См.: material-ui.com/components/icons/#icon-font-icons

Vajk Hermecz 13.01.2020 17:15

«Правильный ответ» печатает для меня только строку props.iconName, не показывает фактическую иконку.

Jonas Rosenqvist 18.08.2020 19:23

@jonasRosenvist, вам также нужно включить ссылку в свой код: <link rel = "stylesheet" href = "fonts.googleapis.com/icon?family=Material+Значки" />

Patrice Thimothee 25.02.2021 10:01

это решение сработало для меня - <Icon>сохранить</Icon>; Имя значка должно быть в нижнем регистре без суффикса «Значок». Что-то вроде ChevronRight — нужно изменить на chevron_right. Вы импортировали файл CSS material_icon в index.js

vkt 16.08.2021 07:35

Как указано в комментариях к ответу Кларк выше, решение, использующее компонент Icon, будет использовать шрифтовую версию значков Material-UI, которая не содержит полного набора значков.

Использование того же метода для получения правильного имени значка (позаимствованного из Кларк) в сочетании с React.createElement делает свое дело. Я сделал это в TypeScript, в ванильном javascript это еще проще. Вот компонент в версии TS (dynamicIcon.tsx), также доступный в это репо:

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).

thclark 26.01.2021 08:43

Другие вопросы по теме