Je veux transformer chaque ListItem
d'un composant List
en un composant Link
.
J'ai un composant Drawer
composé d'un composant List
,
Cette liste est composée de 4 ListItem
s.
Ce que je veux, c'est convertir chaque ListItem
en un routeur React Link
.
J'ai essayé de modifier la méthode onClick du tiroir, d'obtenir l'ID du ListItem cliqué, puis de changer l'emplacement de la fenêtre par programme en fonction de l'ID.
Mais je pense que cette approche est plus simple que les concepts de réaction.
J'ai aussi essayé d'ajouter Link
à component
prop dans ListItem
, mais cela a abouti à une erreur (j'ai vu que vous avez utilisé un prop dans component
dans docs).
Quelle est la manière recommandée pour répondre à cette exigence?
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { withStyles } from 'material-ui/styles';
import Drawer from 'material-ui/Drawer';
import List, { ListItem, ListItemIcon, ListItemText } from 'material-ui/List';
import Face from 'material-ui-icons/Face';
import Person from 'material-ui-icons/Person';
import Assignment from 'material-ui-icons/Assignment';
import Link from 'react-router-dom/Link';
import { FormattedMessage } from 'react-intl';
const styles = {
list: {
width: 250,
flex: 'initial',
},
};
class UndockedDrawer extends Component {
constructor() {
super();
this.onClick = this.onClick.bind(this);
}
onClick(e, data) {
console.log(data);
this.props.onRequestClose();
}
render() {
const classes = this.props.classes;
const sidebarListItems = (
<div>
<ListItem button >
<ListItemIcon>
<Person />
</ListItemIcon>
<ListItemText primary={<FormattedMessage id="user" />} />
</ListItem>
<ListItem button>
<ListItemIcon>
<Assignment />
</ListItemIcon>
<ListItemText primary={<FormattedMessage id="consultant" />} />
</ListItem>
<ListItem button>
<ListItemIcon>
<Face />
</ListItemIcon>
<ListItemText primary={<FormattedMessage id="student" />} />
</ListItem>
</div>
);
const sidebarList = (
<div>
<List className={classes.list} >
{sidebarListItems}
</List>
</div>
);
return (
<div>
<Drawer
anchor="right"
open={this.props.open}
onRequestClose={this.props.onRequestClose}
onClick={this.onClick}
>
{sidebarList}
</Drawer>
</div>
);
}
}
UndockedDrawer.propTypes = {
classes: PropTypes.shape({}).isRequired,
open: PropTypes.bool.isRequired,
onRequestClose: PropTypes.func.isRequired,
};
export default withStyles(styles)(UndockedDrawer);
J'ai compris, je peux envelopper ListItem
dans un Link
comme suit:
<Link to="users" style={{ textDecoration: 'none' }}>
<ListItem button >
<ListItemIcon>
<Person />
</ListItemIcon>
<ListItemText primary={<FormattedMessage id="user" />} />
</ListItem>
</Link>
Avec cette approche, la méthode onClick sera également déclenchée.
Des suggestions ou des améliorations?
J'ai compris, je peux envelopper ListItem dans un lien comme suit
Cette solution n'est pas sémantiquement valide. Jetez un œil à la façon dont nous traitons le problème dans la documentation:
Vous pouvez également essayer celui-ci
Ceci est couvert dans la documentation: https://material-ui.com/components/buttons/#third -party-routing-library.
import React from 'react';
import { MemoryRouter as Router } from 'react-router';
import { Link, LinkProps } from 'react-router-dom';
import ListItem from '@material-ui/core/ListItem';
import { Omit } from '@material-ui/types';
// The usage of React.forwardRef will no longer be required for react-router-dom v6.
// see https://github.com/ReactTraining/react-router/issues/6056
const AdapterLink = React.forwardRef<HTMLAnchorElement, LinkProps>((props, ref) => (
<Link innerRef={ref as any} {...props} />
));
const CollisionLink = React.forwardRef<HTMLAnchorElement, Omit<LinkProps, 'innerRef' | 'to'>>(
(props, ref) => <Link innerRef={ref as any} to="/getting-started/installation/" {...props} />,
);
export default function ButtonRouter() {
return (
<Router>
<ListItem color="primary" component={AdapterLink} to="/">
Simple case
</ListItem>
<ListItem component={CollisionLink}>Avoids props collision</ListItem>
</Router>
);
}
Je ne le vois pas dans la documentation:
https://material-ui-next.com/demos/lists/
https://material-ui-next.com/demos/drawers/
C'est une chose courante lors de l'utilisation de React Router, mais on ne sait pas comment utiliser NavLink
dans un ListItem
.
Un Button
avec component
prop?
Et les accessoires de bouton et les accessoires de composant sont mélangés ensemble sur la même balise JSX?
Quel est ce genre de mixin?
Pourquoi si complexe?
Lorsque vous utilisez la solution de component={Link}
comme @oliviertassinari le suggère, le style est foiré:
(Dans l'image, la souris survole "Build" mais le deuxième élément est souligné ...)
@ilyador Ce problème de style de lien d'interface utilisateur a été résolu.
@ zhangwei900808 Non, c'est toujours faux sémantiquement, cela génère <ul><a ..>...
https://codesandbox.io/s/lpwq74p30m
Utilisez simplement la réponse fournie ci-dessus
@oliviertassinari Y aurait-il un moyen plus simple de faire:
const styles = {
li: {
'&:hover': {
backgroundColor: 'transparent',
},
},
};
// ...
<MenuItem disableGutters className={classes.li}>
<Button component={Link} to="/logout" ...
Pour éviter un double effet de survol, sur les MenuItem
et les Button
(qui ont encore une légère gouttière / rembourrage, autre problème)
Parce que c'est encombrant
démo: https://codesandbox.io/s/nk834yk5pl (sans utiliser component={Link} to="/..."
mais c'est pareil)
@caub Pourquoi introduisez-vous un composant Button supplémentaire? Vous pouvez utiliser la propriété de composant sur le MenuItem.
@oliviertassinari car ul > a
n'est pas valide html5 https://codesandbox.io/s/lpwq74p30m
@caub nav > a
est valide.
Ok, merci, très bien https://codesandbox.io/s/lpwq74p30m
Voici la solution qui a résolu mon problème
<List>
{menus.map((menu: any, index: any) => {
return (
<ListItem
key={index}
{...{ to: menu.link }}
component={Link}
button={true}
>
<ListItemIcon>{menu.icon}</ListItemIcon>
<ListItemText primary={menu.text} />
</ListItem>
);
})}
</List>
Utilisez donc simplement ListItem comme
** {... {vers: menu.link}} **
composant = {Link}
bouton = {true}
>
import {Link} from 'react-router-dom' <ListItem component={Link} to="/" button> // or <ListItem component={props => <Link to="/" {...props} />} button>
@mehrdaad @oliviertassinari Ça a marché ^ _ ^
C'était parfait pour moi. Merci!
La réponse la plus votée a échoué après la migration de MUI v4 (je suis sur 4.3.1) en raison de "Les composants de fonction ne peuvent pas recevoir de références. Les tentatives d'accès à cette référence échoueront. Voulez-vous utiliser React.forwardRef ()?
J'ai remplacé le composant NavLink
par un wrapper comme ceci:
import React, { Component } from "react"
import { NavLink } from "react-router-dom"
/**
* React Router Nav Link wrapper to forward the ref to fix "Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?"
*
* From https://material-ui.com/guides/composition/#caveat-with-refs
*/
class NavLinkMui extends Component {
render() {
const { forwardedRef, ...props } = this.props
return <NavLink {...props} ref={forwardedRef} />
}
}
export default NavLinkMui
Usage:
<ListItem
button
component={NavLinkMui}
to='/'
>
<ListItemIcon>
<SlideshowIcon />
</ListItemIcon>
</ListItem>
@HugoGresse Oui, vous devez utiliser l'API forward ref. Vous devriez pouvoir trouver des exemples dans la documentation. J'ai mis à jour https://github.com/mui-org/material-ui/issues/7956#issuecomment -326908167 avec une réponse à jour. Faites-nous savoir si tout va bien.
@oliviertassinari c'est ce qu'il a fait.
J'ai toujours un problème avec la solution forwardRef ou le composant un où la couleur du texte du bouton ne prend pas en compte la couleur de la palette de thème. La couleur du texte doit être blanche pour correspondre à palette.type: 'dark'
, mais elle est blanche.
Probablement lié à un changement sur MUI car sans les accessoires component
j'ai toujours le problème.
Pour ceux qui lisent ici, vous pouvez passer des accessoires supplémentaires au ListItemText ...
<ListItemText
primaryTypographyProps={{
color: 'textPrimary'
}}
primary="Dashboard"
/>
BTW, votre exemple est maintenant dans TS.
Voici la solution qui a résolu mon problème
<List> {menus.map((menu: any, index: any) => { return ( <ListItem key={index} {...{ to: menu.link }} component={Link} button={true} > <ListItemIcon>{menu.icon}</ListItemIcon> <ListItemText primary={menu.text} /> </ListItem> ); })} </List>
Utilisez donc simplement ListItem comme
clé = {index}
** {... {vers: menu.link}} **
composant = {Link}
bouton = {true}
>
button={true}
rend simplement le comportement de l'interface utilisateur des tiroirs identique à l'absence de lien.
Pour les autres essayant de faire cela dans Typescript:
Un exemple simple utilisant la propriété du composant ListItem pour spécifier un
import { NavLink } from "react-router-dom";
<List>
<ListItem button={true} {...{ component: NavLink, to: "/Somewhere" }}>
<ListItemIcon>
<ShoppingCartIcon />
</ListItemIcon>
<ListItemText primary="Orders" />
</ListItem>
</List>
ou bien si vous souhaitez simplement utiliser une fonction onClick sur le ListItem par exemple:
<List>
<ListItem button={true} {...{ onClick: () => alert("foo") }}>
<ListItemIcon>
<DashboardIcon />
</ListItemIcon>
<ListItemText primary="Dashboard" />
</ListItem>
</List>
''
Cela a fonctionné pour moi
const NavLinkMui = React.forwardRef((props, ref) => (
<NavLink {...props} activeClassName="Mui-selected" ref={ref} />
))
<ListItem button component={NavLinkMui} to={to}>{text}</ListItem>
La réponse la plus votée a échoué après la migration de MUI v4 (je suis sur 4.3.1) en raison de "Les composants de fonction ne peuvent pas recevoir de références. Les tentatives d'accès à cette référence échoueront. Voulez-vous utiliser React.forwardRef ()?
J'ai remplacé le composant
NavLink
par un wrapper comme ceci:import React, { Component } from "react" import { NavLink } from "react-router-dom" /** * React Router Nav Link wrapper to forward the ref to fix "Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?" * * From https://material-ui.com/guides/composition/#caveat-with-refs */ class NavLinkMui extends Component { render() { const { forwardedRef, ...props } = this.props return <NavLink {...props} ref={forwardedRef} /> } } export default NavLinkMui
Usage:
<ListItem button component={NavLinkMui} to='/' > <ListItemIcon> <SlideshowIcon /> </ListItemIcon> </ListItem>
Merci @HugoGresse Cela fonctionne parfaitement bien :-)
Commentaire le plus utile
Ceci est couvert dans la documentation: https://material-ui.com/components/buttons/#third -party-routing-library.