1
votes

Routage imbriqué React Router Dom, ou comment passer un slug

J'essaie de transmettre un slug à un composant d'en-tête sans avoir à inclure l'en-tête à chaque sous-composant.

Mon code ressemble à ceci:

slug: "game"

Ce que je veux, c'est que le composant Header sache quel slug a été choisi dans l'une des routes du Switch.

Est-il possible de le faire avec, par exemple, le routage imbriqué?

Meilleur Cordialement, Patrick


Edit:

Ceci est mon composant Header btw:

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

Je veux donner la possibilité aux liens pour inclure la limace. Par exemple, href = / game doit être href =: slug / game alors.

Et sachez que l'en-tête est chargé avant le changement.


Edit2:

Au moins ceci:

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

me donnera accès à l'emplacement où se trouve le slug. Mais cela ne semble pas être le moyen le plus propre. De plus, match.params ne contient pas le slug, même avec l'exportation withRouter . Pourquoi?

Ma solution jusqu'à ce que je sache mieux (ne fonctionne pas)

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

....


export default withRouter(Header);

Cela entraînera la confusion de l'URL après quelques clics, la localisation sera concaténé encore et encore des URLs résultantes comme /myslug,game,player,...

Solution finale

Eh bien, j'ai obtenu la solution finale ci-dessous qui est: p >

Enveloppez l'en-tête à son emplacement spécifique dans Route

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

....

export default withRouter(Header);

Accédez ensuite à props.match.params dans le composant 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;


3 commentaires

Utilisez useParams ou obtenez les paramètres à partir de l'itinéraire match prop du Router .


const Header = (props) => {console.log (props.match.params.slug) Cela ne fonctionne pas cependant. TypeError: Impossible de lire la propriété 'params' non définie


Header n'est pas rendu par une Route , vous devez donc utiliser le hook useParams ou le HOC withRouter pour obtenir les paramètres de correspondance du routeur le plus proche. Ou simplement rendre l ' En-tête en une correspondance à tous les Route , c'est-à-dire .


3 Réponses :


0
votes

Essayez d'utiliser useParams () pour récupérer le slug.


2 commentaires

Cela ne fonctionne pas car l'en-tête est chargé avant le commutateur. Il n'y a pas encore de slug lors du rendu de l'en-tête.


Vous voudrez peut-être vérifier avec Routeur alors. Je pense que c'est peut-être ce que vous recherchez.



0
votes

Essayez de faire comme ceci:

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


0 commentaires

2
votes

Problème

L ' En-tête n'est pas rendu sur une route, il n'a donc accès à aucun des accessoires de route, en particulier aux paramètres de la route. Il doit également être rendu sur une Route qui correspond à un chemin qui spécifie le paramètre de route "slug".

Solution

Transformez l ' En-tête en un Route qui spécifie à la fois un chemin correspondant à tous les un chemin pouvant correspondre à un slug L'ordre est important, spécifiez donc le chemin avec le slug en premier afin qu'il puisse être mis en correspondance avant les routes moins spécifiques (comme les règles pour le Switch).

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

h1 >


12 commentaires

Les options 1 et 2 me donneront undefined. UseParams () peut simplement restituer le splug qui se trouve dans le routeur, mais pas l'en-tête. L'option 2 n'aura pas de slug dans le match des accessoires (je suppose que pour la même raison). L'option 3 ne fonctionnera pas car elle rompt ma disposition de grille.


Vraisemblablement, votre routeur encapsule votre application , si ce n'est pas le cas, veuillez ajouter les détails importants sur l'emplacement de votre routeur tel quel le composant qui contient les données d'itinéraire, c'est-à-dire le paramètre d'itinéraire "slug".


Il encapsule en fait l'application: ` ` dans index.js


Cela omettra cependant de rendre mon contenu principal! Et le comportement de rendu diffère selon la position dans le commutateur.


@PatrickHener Réponse mise à jour avec la façon dont le composant Header peut accéder au slug. Les composants Route n'ont pas beaucoup d'aspect visuel, le cas échéant, donc si le rendu de votre En-tête dans une Route perturbe la disposition de la grille, c'est probablement parce que vos composants font des hypothèses sur leurs composants parents. Je suppose qu'il essaie simplement d'hériter de certains CSS.


Switch ne correspond et renvoie que la première correspondance .... ne mettez pas le Header dans votre Switch si vous voulez qu'il soit toujours rendu. L'emballage de Header dans Route sert simplement à accéder aux accessoires de route.


Oh d'accord, je comprends ça. Alors je l'ai emballé à sa position d'origine. Mais là encore, useParams () me donnera une erreur.


Eh bien, je peux alors y accéder via props.match.params. Voilà la solution!


Quelle est / quelle était l'erreur que vous voyiez en utilisant le hook? Si dans une route, le hook et l'accessoire de correspondance devraient fonctionner à peu près de la même manière.


L'erreur était TypeError: Object (...) n'est pas une fonction à la ligne où il y avait const {slug} = useParams ()


Ohh facepalm moi stupide! Je l'ai importé de react pas de react-router-dom. Maintenant, useParams fonctionne aussi.


@PatrickHener Je vois. J'allais dire que vous devez être sur React v16.8 + et sur la version v5 de react-router-dom pour utiliser les hooks.