【问题标题】:Integrating react router with material ui is not working将反应路由器与材料 ui 集成不起作用
【发布时间】:2020-11-29 01:11:19
【问题描述】:

我正在尝试将 react-router 与侧边栏菜单中的材质 ui 集成,但它不起作用。当我单击菜单项时,只有 url 更改但组件不加载。我使用 [https://material-ui.com/guides/composition/#link] 上的指南进行了尝试,但每次尝试更改代码中的某些内容时都会得到奇怪的结果。我的应用组件如下,

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

【问题讨论】:

  • 您的菜单项上是否需要有component 属性?我在家里看到component: HomePage
  • 我已经把它以编程方式路由它。目前我没有使用它

标签: reactjs react-router material-ui


【解决方案1】:

如果你想指向另一个组件,组件 Menu 必须在 Router 内。

【讨论】:

  • 哪个菜单组件?
  • 在文件layout.js中。将标签Router移出作为该组件的父标签。
  • 你能把你的代码放在codepen.io上吗?所以我们可以看看这个。
【解决方案2】:

@Yogendra Kumar 这个答案是这个post 的延续。我将使用相同的代码和增强功能来添加对 React Router 的支持。


首先,我会将SingleLevel 组件更改为使用react-router-dom 中的Link 组件。这可以通过将component={Link} 传递给ListItem 来完成。另外值得注意的是,如果当前项目没有to属性,我希望用户被重定向到404页面。

阅读有关将react-router-dom 集成到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>
  );
};

MultiLevelListItem 组件不需要此更改,因为我们不希望在单击项目时将用户链接到页面,而是仅显示其折叠的项目。

接下来,我将创建一个 Routes 组件,该组件将包含我的所有路由配置。

react-router-domdocs

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

最后,我将App.js 文件重命名为Nav.js,因为我不想App.js 拥有这些代码

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,这个解决方案没有考虑来自menu.jscomponent 属性。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-11-08
    • 2017-09-02
    • 2019-04-15
    • 2016-12-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多