Как вернуть строку в качестве компонента в react?

#reactjs #material-ui

#reactjs #материал-пользовательский интерфейс

Вопрос:

У меня есть несколько навигационных ссылок в виде JSON-файла, а также несколько значков материалов с названиями ссылок. Я пытаюсь импортировать значки динамически и отображать их как компонент MUI. Я не совсем понимаю этого.

Что мне нужно?

  • Я должен иметь возможность импортировать значки, динамически извлекаемые из файла json.
  • Я должен быть в состоянии отобразить соответствующий компонент MUI из того же json-файла.

Любая помощь была бы признательна.

 import React from "react";
import NavLinks from "../src/data/navlinks.json";
import { useState } from "react";
import {
  Button,
  Grid,
  Drawer,
  List,
  ListItem,
  ListItemIcon,
  ListItemText,
  IconButton,
} from "@material-ui/core";
import MenuIcon from "@material-ui/icons/Menu";
import Link from "./muiCustomComponents/Link";

NavLinks.map(
  (item) => `import {${item.icon}Icon} from "@material-ui/icons/${item.icon}"`
);

const SideNav = () => {

  return (
    <>
      <IconButton
        color="inherit"
        aria-label="delete"
      >
        <MenuIcon />
      </IconButton>
      <Drawer anchor="left" open onClose={toggleDrawer(false)}>
        <List style={{ width: 250 }}>
          {NavLinks.map((item, index) => {
            return (
              <ListItem button key={index} component={Link} href={item.url}>
                <ListItemIcon>{`<${item.icon} />`}</ListItemIcon>
                <ListItemText primary={item.name} />
              </ListItem>
            );
          })}
        </List>
      </Drawer>
    </>
  );
};

export default SideNav;
 

navlinks.json

 [{
    "name": "About Us",
    "url" : "/about",
    "icon": "Info"
},
{
    "name": "Committee",
    "url" : "/committee",
    "icon": "Group"
},
{
    "name": "Speakers",
    "url" : "/speakers",
    "icon": "RecordVoiceOver"

},
{
    "name": "Call for Papers",
    "url" : "/call-for-papers",
    "icon": "Announcement"
}
]
 

Ответ №1:

в этом случае я бы заменил файл json обычным файлом js, например:

 const something = [{
    "name": "About Us",
    "url" : "/about",
    "icon": "Info"
},
{
    "name": "Committee",
    "url" : "/committee",
    "icon": "Group"
},
{
    "name": "Speakers",
    "url" : "/speakers",
    "icon": "RecordVoiceOver"

},
{
    "name": "Call for Papers",
    "url" : "/call-for-papers",
    "icon": "Announcement"
}
]

export default something
 

и я бы импортировал компонент из material Ui в этот файл.

Комментарии:

1. В реальном проекте я могу получать данные json с реального сервера. Я думаю, преобразование в объект js может оказаться бесполезным.

2. Да, но в реальных проектах вы бы импортировали компоненты icons из material ui непосредственно в компонент SIdeNav. Я думаю, они не будут поступать из json на сервере.

Ответ №2:

попробуйте это

 import * as React from 'react';
import * as Icons from "@material-ui/icons";

const DynamicIcon=({icon, ...props})=>{
  if (Icons[icon]){
    return React.createElement(Icons[icon], props);
  }
  else {
    return <></>
  }
}

const icons = ["Archive", "ArrowBack","Apple","Apps","AccessAlarm"];
export default function Test() {
  return (
  <div>
    {icons.map((icon, index)=>
        <DynamicIcon key={index} icon={icon} color="primary"></DynamicIcon>
    )}
  </div>
  );
}
 

Комментарии:

1. Разве импорт всех значков из material ui не является вопросом большого объединения?

Ответ №3:

вы можете использовать функцию импорта для динамической загрузки значка и использовать props.icon, чтобы задать имя значка значка материала

 import * as React from "react";
import { useEffect, useState } from "react";
function AsyncIcon(props) {
  const { icon, ...others } = props;
  const [Component, setComponent] = useState(null);
  const [loaded, setLoaded] = useState(false);

  useEffect(() => {
    let iconName = props.icon.replace(/Icon$/, "");
    if (!loaded) {
      import(`@material-ui/icons/${iconName}`).then((module) => {
        setComponent(module.default);
      });
    }
  }, [loaded, props.icon]);
  return Component ? <Component {...others}></Component> : <></>;
}
const icons = ["Archive", "ArrowBack", "Apple", "Apps", "AccessAlarm"];
export default function Test() {
  const [iconName, setIconName] = useState(icons[0]);
  return (
    <div>
      <AsyncIcon icon={iconName} color="secondary"></AsyncIcon>
      <button onClick={()=>{
        setIconName(icons[Math.floor(Math.random()*10) % icons.length]);
      }}>test </button>
      {icons.map((icon, index) => (
        <AsyncIcon key={index} icon={icon} color="primary"></AsyncIcon>
      ))}
    </div>
  );
}