【问题标题】:What's the best way to separate the routes in react-router-dom?在 react-router-dom 中分离路由的最佳方法是什么?
【发布时间】:2021-07-14 09:58:19
【问题描述】:

我用路由做了一个小任务,当我在 URL 中输入 / 时,它会将我重定向到登录页面,当我输入 /dashboard 时,它会将我重定向到具有材料 UI 持久抽屉的仪表板。但是当我在 2 个组件中使用 browserRouter 时,我的做法完全错误,但理想情况下,它应该只在根组件中,因此 当我第一次单击抽屉中的某个链接时,它会在仪表板中呈现该组件,但是当我刷新页面时它什么也不加载 我看到一个示例 here 路由组织得很好,就像我点击登录时,他们的 URL 是 auth/login,当我注册时,他们的 URL 是 auth/signup,当我去的时候,仪表板也是如此仪表板他们的网址是dashboard/app,当我点击其他链接项目时,模式相同dashboard/link

请参阅上面的示例以了解我要解释的内容。

你也可以在codesandbox上看到我的代码here

简而言之:我想以auth/loginauth/signupdashboard/appdashboard/profile等方式组织我的路线。

我的 App.js

import { Switch, Route } from "react-router-dom";

import AppDrawerBar from "./compponents/AppDrawerBar";
import Login from "./pages/Login";
import "./styles.css";

export default function App() {
  return (
    <div className="App">
      <Switch>
        <Route exact path="/" exact component={Login} />
        <Route path="/dashboard" component={AppDrawerBar} />
      </Switch>
    </div>
  );
}

Login.js

import React from "react";

const Login = () => {
  return <h1>Login Page</h1>;
};

export default Login;

Dashboard.js,其中链接默认包含 home 组件的路由以及关于组件的路由

import React from "react";
import clsx from "clsx";
import { makeStyles, useTheme } from "@material-ui/core";
import Drawer from "@material-ui/core/Drawer";
import CssBaseline from "@material-ui/core/CssBaseline";
import AppBar from "@material-ui/core/AppBar";
import Toolbar from "@material-ui/core/Toolbar";
import List from "@material-ui/core/List";
import Typography from "@material-ui/core/Typography";
import Divider from "@material-ui/core/Divider";
import IconButton from "@material-ui/core/IconButton";
import MenuIcon from "@material-ui/icons/Menu";
import ChevronLeftIcon from "@material-ui/icons/ChevronLeft";
import ChevronRightIcon from "@material-ui/icons/ChevronRight";
import ListItem from "@material-ui/core/ListItem";
import ListItemIcon from "@material-ui/core/ListItemIcon";
import ListItemText from "@material-ui/core/ListItemText";
import InboxIcon from "@material-ui/icons/MoveToInbox";
import MailIcon from "@material-ui/icons/Mail";
import Home from "../pages/Home";
import About from "../pages/About";
import { BrowserRouter, Link, Route, Switch } from "react-router-dom";

const drawerWidth = 240;

const useStyles = makeStyles((theme) => ({
  root: {
    display: "flex"
  },
  appBar: {
    transition: theme.transitions.create(["margin", "width"], {
      easing: theme.transitions.easing.sharp,
      duration: theme.transitions.duration.leavingScreen
    })
  },
  appBarShift: {
    width: `calc(100% - ${drawerWidth}px)`,
    marginLeft: drawerWidth,
    transition: theme.transitions.create(["margin", "width"], {
      easing: theme.transitions.easing.easeOut,
      duration: theme.transitions.duration.enteringScreen
    })
  },
  menuButton: {
    marginRight: theme.spacing(2)
  },
  hide: {
    display: "none"
  },
  drawer: {
    width: drawerWidth,
    flexShrink: 0
  },
  drawerPaper: {
    width: drawerWidth
  },
  drawerHeader: {
    display: "flex",
    alignItems: "center",
    padding: theme.spacing(0, 1),
    // necessary for content to be below app bar
    ...theme.mixins.toolbar,
    justifyContent: "flex-end"
  },
  content: {
    flexGrow: 1,
    padding: theme.spacing(3),
    transition: theme.transitions.create("margin", {
      easing: theme.transitions.easing.sharp,
      duration: theme.transitions.duration.leavingScreen
    }),
    marginLeft: -drawerWidth
  },
  contentShift: {
    transition: theme.transitions.create("margin", {
      easing: theme.transitions.easing.easeOut,
      duration: theme.transitions.duration.enteringScreen
    }),
    marginLeft: 0
  }
}));

export default function PersistentDrawerLeft() {
  const classes = useStyles();
  const theme = useTheme();
  const [open, setOpen] = React.useState(true);

  const handleDrawerOpen = () => {
    setOpen(true);
  };

  const handleDrawerClose = () => {
    setOpen(false);
  };

  return (
    <BrowserRouter>
      <div className={classes.root}>
        <CssBaseline />
        <AppBar
          position="fixed"
          className={clsx(classes.appBar, {
            [classes.appBarShift]: open
          })}
        >
          <Toolbar>
            <IconButton
              color="inherit"
              aria-label="open drawer"
              onClick={handleDrawerOpen}
              edge="start"
              className={clsx(classes.menuButton, open && classes.hide)}
            >
              <MenuIcon />
            </IconButton>
            <Typography variant="h6" noWrap>
              Persistent drawer
            </Typography>
          </Toolbar>
        </AppBar>
        <Drawer
          className={classes.drawer}
          variant="persistent"
          anchor="left"
          open={open}
          classes={{
            paper: classes.drawerPaper
          }}
        >
          <div className={classes.drawerHeader}>
            <IconButton onClick={handleDrawerClose}>
              {theme.direction === "ltr" ? (
                <ChevronLeftIcon />
              ) : (
                <ChevronRightIcon />
              )}
            </IconButton>
          </div>
          <Divider />
          <List>
            <ListItem button key="home" to="/home" component={Link}>
              <ListItemIcon>
                <MailIcon />
              </ListItemIcon>
              <ListItemText primary="Home" />
            </ListItem>
          </List>
          <Divider />
          <List>
            <ListItem button key="about" to="/about" component={Link}>
              <ListItemIcon>
                <InboxIcon />
              </ListItemIcon>
              <ListItemText primary="About" />
            </ListItem>
          </List>
        </Drawer>
        <main
          className={clsx(classes.content, {
            [classes.contentShift]: open
          })}
        >
          <div className={classes.drawerHeader} />
          <Route path="/home" exact component={Home} />
          <Route path="/about" component={About} />
        </main>
      </div>
    </BrowserRouter>
  );
}

Home.js

import React from "react";

const Home = () => {
  return <h1>Home Page</h1>;
};

export default Home;

关于.js

import React from "react";

const About = () => {
  return <h1>About Page</h1>;
};

export default About;

【问题讨论】:

  • 所以你有 2 个根路径,“/dashboard”和“/”,以及一些组件......你有没有尝试为你想要渲染的每个组件的每个路径定义特定的路由?你试过什么?
  • @DrewReese,我正在学习对路线做出反应,所以我仍然不知道很多事情。是的,两个根路径。您可以在 app.js 中看到我尝试过的内容,它是一些简单的路由,而第 97 行的组件/仪表板中的其他路由...codesandbox.io/s/routing-with-drawer-9fpmw?file=/src/App.js

标签: javascript reactjs react-router material-ui react-router-dom


【解决方案1】:

如果我正确理解您的问题,您正在尝试创建嵌套路由,即您希望 About 组件呈现在“/dashboard”子域中的嵌套路由上,例如“/dashboard/about”。

问题

您已将AppDrawerBar 组件包装到第二个嵌套路由器中。这可能会扰乱整个应用程序路由,因为包装应用程序的外部路由器不知道嵌套的内部路由器正在处理的任何事情。它也不嵌套路由路径。

解决方案

  1. 创建一个新的Dashboard 组件作为“登陆”页面并管理嵌套路径。您还需要将AppDrawerBar 移动到此处,因为这是处理嵌套路线导航的原因。

    import { Switch, Redirect, Route, useRouteMatch } from "react-router-dom";
    import Home from "./Home";
    import About from "./About";
    import AppDrawerBar from "../components/AppDrawerBar";
    
    const Dashboard = () => {
      const { path } = useRouteMatch();
      return (
        <>
          <AppDrawerBar>
            <Switch>
              <Route path={`${path}/about`} component={About} />
              <Route path={`${path}/home`} exact component={Home} />
              <Redirect to={`${path}/home`} />
            </Switch>
          </AppDrawerBar>
        </>
      );
    };
    
    export default Dashboard;
    
  2. 不要将AppDrawerBar 与另一个Router 包装在一起,并删除其中定义的Route 组件。相反,渲染传递的孩子。更新链接以使用当前路由匹配中的url 来计算嵌套链接。

    function PersistentDrawerLeft({ children }) {
      ...
    
      const { url } = useRouteMatch();
    
      ...
    
      return (
        <div className={classes.root}
    
          ...
    
          <Drawer
            className={classes.drawer}
            variant="persistent"
            anchor="left"
            open={open}
            classes={{
              paper: classes.drawerPaper
            }}
          >
            <div className={classes.drawerHeader}>
              <IconButton onClick={handleDrawerClose}>
                {theme.direction === "ltr" ? (
                  <ChevronLeftIcon />
                ) : (
                  <ChevronRightIcon />
                )}
              </IconButton>
            </div>
            <Divider />
            <List>
              <ListItem button key="home" to={`${url}/home`} component={Link}>
                ...
              </ListItem>
            </List>
            <Divider />
            <List>
              <ListItem button key="about" to={`${url}/about`} component={Link}>
                ...
              </ListItem>
            </List>
          </Drawer>
          <main
            className={clsx(classes.content, {
              [classes.contentShift]: open
            })}
          >
            <div className={classes.drawerHeader} />
            {children}
          </main>
        </div>
      );
    }
    

演示

【讨论】:

  • 非常感谢,我正在努力学习和实施它。我真的很感激:-)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-28
  • 2021-04-03
  • 2012-10-14
  • 2021-06-26
  • 2019-05-30
  • 2018-06-08
相关资源
最近更新 更多