简体   繁体   English

React Router Dom 嵌套路由,或者如何传递一个 slug

[英]React Router Dom nested routing, or how to pass a slug

I am trying to pass a slug to a header component without having to include the header to each and every subcomponent.我正在尝试将 slug 传递给 header 组件,而不必将 header 包含到每个子组件中。

My code looks like this:我的代码如下所示:

const App = () => {
  return (
    <>
      <Grid container direction="column">
        <Grid item>
          <Header />
        </Grid>
        <Grid item container>
          <Grid item xs={false} md={2} />
          <Grid item xs={12} md={8}>
            <Switch>
              <Route exact path="/" component={IntroPage} />
              <Route exact path="/:slug" component={StartPage} />
              <Route path="/:slug/index" component={StartPage} />
              <Route path="/:slug/player" component={PlayerPage} />
              <Route path="/:slug/game" component={GamePage} />
              <Route path="/:slug/scoreboard" component={ScoreboardPage} />
              <Route path="/:slug/controller" component={ControllerPage} />
              <Route path="/:slug/settings" component={SettingsPage} />
              <Route path="/:slug/credits" component={CreditsPage} />
              <Route component={PageNotFound} />
            </Switch>
          </Grid>
          <Grid item xs={false} md={2} />
        </Grid>
        <ToastContainer autoClose={3000} hideProgressBar />
      </Grid>
      <Grid container direction="column">
        <Footer />
      </Grid>
    </>
  );
};

export default App;

What I want is the Header component to know what slug was chosen in one of the routes within the Switch.我想要的是 Header 组件,以了解在 Switch 的其中一条路由中选择了哪些 slug。

Is there a possibility to do this with for example nested routing?例如嵌套路由是否有可能做到这一点?

Best regards, Patrick最好的问候,帕特里克


Edit:编辑:

This is my Header component btw:这是我的 Header 组件顺便说一句:

const Header = (props) => {
  console.log(props.match.params.slug)
  const classes = useStyles();
  const [open, setOpen] = useState();

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

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

  return (
    <div className={classes.root}>
      <AppBar
        position="static"
        className={clsx(classes.appBar, { [classes.appBarShift]: open })}
      >
        <Toolbar>
          <IconButton
            aria-label="open drawer"
            onClick={handleDrawerOpen}
            edge="start"
            className={clsx(classes.menuButton, open && classes.hide)}
          >
            <MenuIcon />
          </IconButton>
          <Typography>Placeholder Banner</Typography>
        </Toolbar>
      </AppBar>
      <Drawer
        variant="persistent"
        anchor="left"
        open={open}
        className={classes.drawer}
        classes={{ paper: classes.drawerPaper }}
      >
        <div className={classes.drawerHeader}>
          <IconButton onClick={handleDrawerClose}>
            <CloseIcon />
          </IconButton>
        </div>
        <Divider />
        <List>
          <ListItem component="a" href="/" button key="start">
            <ListItemIcon>
              <HomeIcon fontSize="large" />
            </ListItemIcon>
            <ListItemText>Start</ListItemText>
          </ListItem>
          <ListItem component="a" href="/game" button key="game">
            <ListItemIcon>
              <SportsEsportsIcon fontSize="large" />
            </ListItemIcon>
            <ListItemText>Game Setup</ListItemText>
          </ListItem>
          <ListItem component="a" href="/player" button key="player">
            <ListItemIcon>
              <PersonIcon fontSize="large" />
            </ListItemIcon>
            <ListItemText>Player Setup</ListItemText>
          </ListItem>
          <ListItem component="a" href="/settings" button key="settings">
            <ListItemIcon>
              <SettingsIcon fontSize="large" />
            </ListItemIcon>
            <ListItemText>Settings</ListItemText>
          </ListItem>
          <ListItem component="a" href="/credits" button key="credits">
            <ListItemIcon>
              <InfoIcon fontSize="large" />
            </ListItemIcon>
            <ListItemText>Credits</ListItemText>
          </ListItem>
        </List>
      </Drawer>
    </div>
  );
};

export default Header;

I want to give the links the ability to include the slug.我想让链接能够包含蛞蝓。 For example href=/game needs to be href=:slug/game then.例如href=/game需要是href=:slug/game

And please be aware that header is loaded before the switch.请注意,header 是在切换之前加载的。


Edit2:编辑2:

At least this:至少这样:

const Header = (props) => {
  const {match, location, history} = props
  console.log(match)
  console.log(location)
  console.log(history)

....

export default withRouter(Header);

will give me access to the location which has the slug.将让我访问有蛞蝓的位置。 But this appears to not be the cleanest way.但这似乎不是最干净的方法。 Also match.params does not hold the slug, even with withRouter export.即使使用withRouter导出,match.params 也不会保留 slug。 Why is that?这是为什么?

My solution until I know better (Not working)我的解决方案,直到我知道更好(不工作)

const Header = (props) => {
  const { location } = props;
  let pathname = location.pathname
  let slug = pathname.split("/")
  console.log(slug[1]);

....


export default withRouter(Header);

This will cause that the url gets confused after a few clicks cause location will be concatenated again and again resulting ins urls like /myslug,game,player,...这将导致 url 在单击几下后变得混乱,因为位置将一次又一次地连接,从而导致诸如 /myslug、game、player 之类的 ins url...

Final solution最终解决方案

Well I got the final solution from below which is:好吧,我从下面得到了最终解决方案:

Wrap the Header in its specific location into Route将 Header 的特定位置包装到 Route

        <Grid item>
          <Route path={["/:slug", "*"]} component={Header} />
        </Grid>

Then access props.match.params in Header component:然后访问 Header 组件中的 props.match.params :

const Header = (props) => {
  console.log(props.match.params)

this will give:这将给出:

slug: "game"

Issue问题

The Header isn't being rendered on a route so it doesn't have access to any of the route-props, specifically, the route parameters. Header没有在路由上渲染,因此它无法访问任何路由道具,特别是路由参数。 It also needs to be rendered on a Route that matches a path that specifies the "slug" route parameter.它还需要在与指定“slug”路由参数的路径匹配的路由上呈现。

Solution解决方案

Render the Header into a Route that specifies both a match all path and a path that can match with a slug.Header渲染到指定匹配所有路径可以与 slug 匹配的路径的Route中。 Order matter so specify the path with slug first so it can be matched before less specific routes (same as the rules for the Switch ).顺序很重要,因此首先使用 slug 指定路径,以便可以在不太具体的路由之前匹配它(与Switch的规则相同)。

<Route path={["/:slug", '*']} component={Header} />

Try using useParams() to get the slug.尝试使用 useParams() 来获取 slug。

Try do like this:尝试这样做:

<Route 
   exact 
   path='/:slug/player' 
   render={(props) => <PlayerPage {...props}/>}
/>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM