将React Router与物料ui集成不起作用 [英] Integrating react router with material ui is not working
问题描述
我正在尝试在侧边栏菜单中将react-router与材质ui集成在一起,但是它不起作用.当我单击菜单项时,仅url发生更改,但组件未加载.我在[https://material-ui.com/guides/composition/#link]上的指南中进行了尝试,但是每次尝试更改代码中的内容时,都会得到奇怪的结果.我的应用程序组件如下,
layout.js
import React, {useCallback, useState} from 'react';从'clsx'导入clsx;进口 {转变,路线,BrowserRouter作为路由器}来自"react-router-dom";进口 {makeStyles,使用主题}来自"@ material-ui/core/styles";进口 {抽屉,CssBaseline,AppBar,工具栏IconButton,排版,分频器列表,}来自"@ material-ui/core";从'@ material-ui/icons/Menu'导入MenuIcon;从"./menu"导入{MenuItem};从"./menuitems"导入{menu};从"./DowTheory"导入{TheDowTheory};从"../Home/Home"导入{HomePage};const抽屉宽度= 280;const useStyles = makeStyles((theme)=>({根: {显示:"flex",},appBar:{zIndex:theme.zIndex.drawer + 1过渡:theme.transitions.create([''width','margin'],{缓动:theme.transitions.easing.sharp,持续时间:theme.transitions.duration.leavingScreen,}),},menuButton:{marginRight:36,},隐藏: {显示:无",},抽屉: {宽度:抽屉宽度,flexShrink:0,whiteSpace:"nowrap",},抽屉打开:{宽度:抽屉宽度,过渡:theme.transitions.create('width',{缓动:theme.transitions.easing.sharp,持续时间:theme.transitions.duration.enteringScreen,}),},抽屉关闭:{过渡:theme.transitions.create('width',{缓动:theme.transitions.easing.sharp,持续时间:theme.transitions.duration.leavingScreen,}),overflowX:隐藏",宽度:theme.spacing(7)+ 1[theme.breakpoints.up('sm')]:{宽度:theme.spacing(9)+ 1},},工具栏:{显示:"flex",alignItems:'中心',justifyContent:'flex-end',填充:theme.spacing(0, 1),//内容必须位于应用栏下方... theme.mixins.toolbar,},内容: {flexGrow:1填充:theme.spacing(3),},}));导出const MiniDrawer =()=>{const classes = useStyles();const theme = useTheme();const [open,setOpen] = useState(true);const toggle = useCallback(()=>setOpen(!open),[打开],);返回 (< div className = {classes.root}>< CssBaseline/>< AppBarposition ="fixed"className = {classes.appBar}样式= {{backgroundColor:'white'}}><工具栏>< IconButtoncolor =继承"aria-label =打开抽屉"onClick = {toggle}edge =开始"className = {clsx(classes.menuButton,{[classes.open] :! open,})}样式= {{颜色:'#10375c'}}>< MenuIcon/></IconButton><版式变体="h4".noWrap样式= {{颜色:'#10375c'}}>StockViz</Typography></工具栏></AppBar><抽屉变体=永久的".className = {clsx(classes.drawer,{[classes.drawerOpen]:打开,[classes.drawerClose]:!open,})}类别= {{论文:clsx({[classes.drawerOpen]:打开,[classes.drawerClose]:!open,}),}}>< div className = {classes.toolbar}>< IconButton onClick = {toggle}/></div><除法器/><列表>{menu.map((item,key)=>< MenuItem key = {key} item = {item}/>)}}</列表></抽屉>< main className = {classes.content}>< div className = {classes.toolbar}/><路由器>< Switch><路由精确路径='/'component = {HomePage}/><路由精确路径='/thedowtheory'组件= {TheDowTheory}/></Switch></路由器></main></div>);}
menu.js
从"react"导入React,{forwardRef,Fragment,useMemo,useState};从'@ material-ui/core/styles'导入{makeStyles};从'@ material-ui/core/List'导入列表;从'@ material-ui/core/ListItem'导入ListItem;从 '@material-ui/core/ListItemIcon' 导入 ListItemIcon;从'@ material-ui/core/ListItemText'导入ListItemText;从'@ material-ui/core/Collapse'导入折叠;从'@ material-ui/icons/ExpandLess'导入ExpandLess;从'@ material-ui/icons/ExpandMore'导入ExpandMore;从"./utils"导入{hasChildren};从"@ material-ui/core/Divider"导入除法器;进口 {关联,BrowserRouter作为路由器,}来自"react-router-dom";const useStyles = makeStyles((theme)=>({关联: {textDecoration:无",颜色:theme.palette.text.primary}}))const SingleLevel =({{item})=>{const classes = useStyles();返回 (<路由器><链接到= {item.to} className = {classes.link}>< ListItem按钮>< ListItemIcon> {item.icon}</ListItemIcon>< ListItemText primary = {item.title}/></ListItem></链接></路由器>);};const MultiLevel =({item})=>{const classes = useStyles();const {items:children} = item;const [open,setOpen] = useState(false);const handleClick =()=>{setOpen((prev)=>!prev);};返回 (<路由器><链接到= {item.to} className = {classes.link}>< ListItem按钮onClick = {handleClick}>< ListItemIcon> {item.icon}</ListItemIcon>< ListItemText primary = {item.title}/>{打开 ?< ExpandLess/>:< ExpandMore/>}</ListItem><折叠进入= {打开}超时=自动";unmountOnExit>< List component ='div'禁用填充>{children.map((child,key)=>(< MenuItem key = {key} item = {child}/>))}</列表></折叠></链接></路由器>);};export const MenuItem =({{item})=>{const Component = hasChildren(item)?多层:单层;返回<组件item = {item}/> ;;};
menuitems.js
从"@ material-ui/icons/HomeOutlined"导入HomeOutlinedIcon;从"@ material-ui/icons/LocalLibraryOutlined"导入LocalLibraryOutlinedIcon;从"@ material-ui/icons/TrendingUpOutlined"导入TrendingUpOutlinedIcon;从"@ material-ui/icons/DescriptionOutlined"导入DescriptionOutlinedIcon;从反应"导入React;从"../Home/Home"导入{HomePage};从./DowTheory"导入{TheDowTheory};导出const菜单= [{图标:< HomeOutlinedIcon/> ;,标题:首页",至: '/',组件:首页,项目: []},{图标:< LocalLibraryOutlinedIcon/> ;,标题:教育",项目: [{标题:技术分析",项目: [{标题:简介",组件:技术",到:'/technical'},{标题:陶氏理论",组件:TheDowTheory,到:'/thedowtheory'},{标题:图表和图表模式",组件:图表",制成图表'},{标题:趋势与趋势"趋势线",组成部分:趋势",到:'/trendlines'},{标题:支持与支持"抵抗性',组件:支持",到:'/sandr'},]},{标题:基本面分析",项目: [{标题:简介",组件:技术",到:'/fundamental'},{标题:陶氏理论",组件:技术",到:'/thedowtheory'},{标题:图表和图表模式",组件:技术",制成图表'},{标题:趋势与趋势"趋势线",组件:技术",到:'/trendlines'},{标题:支持与支持"抵抗性',组件:技术",到:'/sandr'},]},{标题:艾略特波浪分析",项目: [{标题:简介",组件:技术",到:'/elliot'},{标题:陶氏理论",组件:技术",到:'/thedowtheory'},{标题:图表和图表模式",组件:技术",制成图表'},{标题:趋势与趋势"趋势线",到:'/trendlines'},{标题:支持与支持"抵抗性',到:'/sandr'},]},]},{图标:<TrendingUpOutlinedIcon/>,到:'/options',组件:选项",标题:选项"},{图标:< DescriptionOutlinedIcon/> ;,到:'/blog',组件:博客",标题:博客"},]
utils.js
import从"react"导入React;导出函数hasChildren(item){const {items:children} = item;如果(孩子===未定义){返回false;}如果(children.constructor!==数组){返回false;}如果(children.length === 0){返回false;}返回true;}
@Yogendra Kumar这个答案是这篇
@Yogendra Kumar,此解决方案未考虑 menu.js
中的 component
属性.
I am trying to integrate react-router with material ui in sidebar menu, but it is not working. When I click on the menu item, only url changes but component doesn't load. I tried it with the guide on [https://material-ui.com/guides/composition/#link], but getting weird results everytime I try to change something in the code. My app components are as below,
layout.js
import React, {useCallback, useState} from 'react';
import clsx from 'clsx';
import {
Switch,
Route,
BrowserRouter as Router
}from 'react-router-dom';
import {
makeStyles,
useTheme
} from '@material-ui/core/styles';
import {
Drawer,
CssBaseline,
AppBar,
Toolbar,
IconButton,
Typography,
Divider,
List,
} from '@material-ui/core';
import MenuIcon from '@material-ui/icons/Menu';
import {MenuItem} from "./menu";
import {menu} from "./menuitems";
import {TheDowTheory} from "./DowTheory";
import {HomePage} from "../Home/Home";
const drawerWidth = 280;
const useStyles = makeStyles((theme) => ({
root: {
display: 'flex',
},
appBar: {
zIndex: theme.zIndex.drawer + 1,
transition: theme.transitions.create(['width', 'margin'], {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.leavingScreen,
}),
},
menuButton: {
marginRight: 36,
},
hide: {
display: 'none',
},
drawer: {
width: drawerWidth,
flexShrink: 0,
whiteSpace: 'nowrap',
},
drawerOpen: {
width: drawerWidth,
transition: theme.transitions.create('width', {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.enteringScreen,
}),
},
drawerClose: {
transition: theme.transitions.create('width', {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.leavingScreen,
}),
overflowX: 'hidden',
width: theme.spacing(7) + 1,
[theme.breakpoints.up('sm')]: {
width: theme.spacing(9) + 1,
},
},
toolbar: {
display: 'flex',
alignItems: 'center',
justifyContent: 'flex-end',
padding: theme.spacing(0, 1),
// necessary for content to be below app bar
...theme.mixins.toolbar,
},
content: {
flexGrow: 1,
padding: theme.spacing(3),
},
}));
export const MiniDrawer = () => {
const classes = useStyles();
const theme = useTheme();
const [open, setOpen] = useState(true);
const toggle = useCallback(
() => setOpen(!open),
[open],
);
return (
<div className={classes.root}>
<CssBaseline />
<AppBar
position="fixed"
className={classes.appBar}
style={{backgroundColor:'white'}}
>
<Toolbar>
<IconButton
color="inherit"
aria-label="open drawer"
onClick={toggle}
edge="start"
className={clsx(classes.menuButton, {
[classes.open]: !open,
})}
style={{color:'#10375c'}}
>
<MenuIcon />
</IconButton>
<Typography variant="h4"
noWrap
style={{color:'#10375c'}}
>
StockViz
</Typography>
</Toolbar>
</AppBar>
<Drawer
variant="permanent"
className={clsx(classes.drawer, {
[classes.drawerOpen]: open,
[classes.drawerClose]: !open,
})}
classes={{
paper: clsx({
[classes.drawerOpen]: open,
[classes.drawerClose]: !open,
}),
}}
>
<div className={classes.toolbar}>
<IconButton onClick={toggle} />
</div>
<Divider />
<List>
{menu.map((item, key) => <MenuItem key={key} item={item} />)}
</List>
</Drawer>
<main className={classes.content}>
<div className={classes.toolbar} />
<Router>
<Switch>
<Route exact path='/' component={HomePage} />
<Route exact path='/thedowtheory' component={TheDowTheory} />
</Switch>
</Router>
</main>
</div>
);
}
menu.js
import React, {forwardRef, Fragment, useMemo, useState} from 'react';
import { makeStyles } from '@material-ui/core/styles';
import List from '@material-ui/core/List';
import ListItem from '@material-ui/core/ListItem';
import ListItemIcon from '@material-ui/core/ListItemIcon';
import ListItemText from '@material-ui/core/ListItemText';
import Collapse from '@material-ui/core/Collapse';
import ExpandLess from '@material-ui/icons/ExpandLess';
import ExpandMore from '@material-ui/icons/ExpandMore';
import {hasChildren} from "./utils";
import Divider from "@material-ui/core/Divider";
import {
Link,
BrowserRouter as Router,
} from "react-router-dom";
const useStyles = makeStyles((theme) => ({
link: {
textDecoration: 'none',
color: theme.palette.text.primary
}
}))
const SingleLevel = ({ item }) => {
const classes = useStyles();
return (
<Router>
<Link to={item.to} className={classes.link}>
<ListItem button>
<ListItemIcon>{item.icon}</ListItemIcon>
<ListItemText primary={item.title} />
</ListItem>
</Link>
</Router>
);
};
const MultiLevel = ({ item }) => {
const classes = useStyles();
const { items: children } = item;
const [open, setOpen] = useState(false);
const handleClick = () => {
setOpen((prev) => !prev);
};
return (
<Router>
<Link to={item.to} className={classes.link}>
<ListItem button onClick={handleClick}>
<ListItemIcon>{item.icon}</ListItemIcon>
<ListItemText primary={item.title} />
{open ? <ExpandLess /> : <ExpandMore />}
</ListItem>
<Collapse in={open} timeout="auto" unmountOnExit>
<List component='div'
disablePadding
>
{children.map((child, key) => (
<MenuItem key={key} item={child} />
))}
</List>
</Collapse>
</Link>
</Router>
);
};
export const MenuItem = ({ item }) => {
const Component = hasChildren(item) ? MultiLevel : SingleLevel;
return <Component item={item} />;
};
menuitems.js
import HomeOutlinedIcon from "@material-ui/icons/HomeOutlined";
import LocalLibraryOutlinedIcon from "@material-ui/icons/LocalLibraryOutlined";
import TrendingUpOutlinedIcon from "@material-ui/icons/TrendingUpOutlined";
import DescriptionOutlinedIcon from "@material-ui/icons/DescriptionOutlined";
import React from "react";
import {HomePage} from "../Home/Home";
import {TheDowTheory} from "./DowTheory";
export const menu = [
{
icon: <HomeOutlinedIcon/>,
title: 'Home',
to: '/',
component: HomePage,
items: []
},
{
icon: <LocalLibraryOutlinedIcon/>,
title: 'Education',
items: [
{
title:'Technical Analysis',
items: [
{
title: 'Introduction',
component: 'Technical',
to: '/technical'
},
{
title: 'The Dow Theory',
component: TheDowTheory,
to: '/thedowtheory'
},
{
title: 'Charts & Chart Patterns',
component: 'Charts',
to: '/chart'
},
{
title: 'Trend & Trend Lines',
component: 'Trends',
to: '/trendlines'
},
{
title: 'Support & Resistance',
component: 'Support',
to: '/sandr'
},
]
},
{
title:'Fundamental Analysis',
items: [
{
title: 'Introduction',
component: 'Technical',
to: '/fundamental'
},
{
title: 'The Dow Theory',
component: 'Technical',
to: '/thedowtheory'
},
{
title: 'Charts & Chart Patterns',
component: 'Technical',
to: '/chart'
},
{
title: 'Trend & Trend Lines',
component: 'Technical',
to: '/trendlines'
},
{
title: 'Support & Resistance',
component: 'Technical',
to: '/sandr'
},
]
},
{
title:'Elliot Wave Analysis',
items: [
{
title: 'Introduction',
component: 'Technical',
to: '/elliot'
},
{
title: 'The Dow Theory',
component: 'Technical',
to: '/thedowtheory'
},
{
title: 'Charts & Chart Patterns',
component: 'Technical',
to: '/chart'
},
{
title: 'Trend & Trend Lines',
to: '/trendlines'
},
{
title: 'Support & Resistance',
to: '/sandr'
},
]
},
]
},
{
icon: <TrendingUpOutlinedIcon/>,
to: '/options',
component: 'Options',
title: 'Options'
},
{
icon: <DescriptionOutlinedIcon/>,
to: '/blog',
component: 'Blog',
title: 'Blog'
},
]
utils.js
import React from "react";
export function hasChildren(item) {
const { items: children } = item;
if (children === undefined) {
return false;
}
if (children.constructor !== Array) {
return false;
}
if (children.length === 0) {
return false;
}
return true;
}
@Yogendra Kumar This answer is a continuation from this post. I will use the same code with enhancement to add support for React Router.
First, I would change my SingleLevel
component to use Link
component from react-router-dom
. This can be done by passing component={Link}
to ListItem
. It's also worth noting that if the current item has no to
property, I would like the user to be redirected to 404 page.
Read the guides on integrating react-router-dom
to material-ui
here.
import { Link } from "react-router-dom";
...
const SingleLevel = ({ item }) => {
return (
<ListItem button component={Link} to={item.to || "/404"}>
<ListItemIcon>{item.icon}</ListItemIcon>
<ListItemText primary={item.title} />
</ListItem>
);
};
This changes is not needed for MultiLevel
's ListItem
component, because we don't want to link user to a page when its item is clicked — but show its collapsed items only.
Next, I would create a Routes
component that will have all of my route configurations.
react-router-dom
docs
Routes.js
export default function Routes() {
return (
<Switch>
<Route exact path="/" component={HomePage} />
<Route path="/thedowtheory" component={TheDowTheory} />
<Route path="/trendlines" component={TrendLines} />
<Route path="/sandr" component={SandR} />
<Route path="/chart" component={Chart} />
<Route path="/404" component={NotFound} />
<Redirect to="/404" />
</Switch>
);
}
Lastly, I will rename the App.js
file to Nav.js
because I wan't App.js
to have these codes instead
import { BrowserRouter as Router } from "react-router-dom";
import Nav from "./Nav";
import Routes from "./Routes";
export default function App() {
return (
<React.Fragment>
<Router>
<Nav />
<Routes />
</Router>
</React.Fragment>
);
}
@Yogendra Kumar, this solution doesn't take account the component
property from menu.js
.
这篇关于将React Router与物料ui集成不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!