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