javascript - 在react-router-dom中分离路由的最佳方法是什么?

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

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

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

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

简而言之:我想以这种方式组织我的路线auth/login auth/signup dashboard/app dashboard/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,其中链接默认包含主页组件的路由以及有关 compoenet 的路由

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;

最佳答案

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

问题

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

解决方案

  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. 不要用另一个 Router 包装 AppDrawerBar 并删除其中定义的 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>
      );
    }
    

演示

Edit whats-the-best-way-to-separate-the-routes-in-react-router-dom

关于javascript - 在react-router-dom中分离路由的最佳方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67174959/

相关文章:

javascript - node-mysql2 Final block 和connection.end()不想被调用

javascript - 当屏幕尺寸大于折叠断点时,如何使导航栏下拉列表水平显示,居中对齐?

javascript - 在 Javascript 中引用变量的元素属性

html - 绝对位置 `div` 内部位置相对父级 `div` 在 chrome 和边缘消失

javascript - 给定错误 : Uncaught TypeError: router. createHref 不是函数,使用 react-bootstrap 导航栏链接到不同页面

reactjs - Golang单页网站服务器

javascript - 在另一个包含的javascript中包含javascript

node.js - 在 Mongoose 中提交一个模型,其中包含一个带有 ObjectID 的数组

javascript - 如何在 React Native 中调整图像大小?

reactjs - React-router 和漂亮的 URL