Material-ui 从 react-router 添加 Link 组件

IT技术 javascript reactjs react-router material-ui
2021-03-16 16:41:32

我正在努力向<Link/>我的 material-ui AppBar添加组件

这是我的导航课:

class Navigation extends Component {
  constructor(props) {
    super(props)
  }

  render() {
    var styles = {
      appBar: {
        flexWrap: 'wrap'
      },
      tabs: {
        width: '100%'
      }
    }

    return (
      <AppBar showMenuIconButton={false} style={styles.appBar}>
        <Tabs style={styles.tabs}>
          <Tab label='Most popular ideas'/>
          <Tab label='Latest ideas' />
          <Tab label='My ideas' />
        </Tabs>
      </AppBar>
    )
  }
}

看起来没问题: 导航栏

标签是可点击的,有流畅的动画,这很酷。但是我如何将它们react-router与它的<Link/>组件连接在一起呢?

我试过添加这样的onChange监听器:

<Tab
  label='My ideas'
  onChange={<Link to='/myPath'></Link>}
/>

但是我收到以下错误:

Uncaught Invariant Violation: Expected onChange listener to be a function, instead got type object

如果我尝试将<Tab/>组件包装<Link/>组件中,则会收到<Tabs/>组件仅接受<Tab/>组件的错误消息

这也不起作用(没有产生错误,但单击 Tab 不会将我带到路径):

<Tab label='Most popular ideas'>
  <Link to='/popular'/>
</Tab>

如何使<Link/>组件与<Tabs>一起工作<AppBar>如果这是不可能的,我可以使用material-ui库中的任何其他组件来形成适当的菜单。

6个回答

对于带有 Typescript 的 Material UI 1.0:请参阅下面@ogglas 的这篇文章

对于带有纯 JS 的 Material-UI 1.0:

<Tabs value={value} onChange={this.handleChange}>
  {
    this.props.tabs.map(
      ({label, path})=><Tab key={label} 
                            label={label} 
                            className={classes.tabLink} 
                            component={Link} 
                            to={path} />
    )
  }
</Tabs>

classes.tabLink定义为:

tabLink : {
    display:"flex",
    alignItems:"center",
    justifyContent:"center"
}

这是如何工作的?

所有继承自 的 mui 1.0 组件都ButtonBase支持一个componentprop,参见ButtonBase这个想法是允许您控制组件呈现为它的包装器/根元素的内容。Tab也具有此功能,尽管在撰写此答案时,该props并未明确记录,但由于Tab继承自ButtonBase,其所有props都会保留(并且文档确实涵盖了这一点)。

的另一个特点ButtonBase是所有额外的props,不是由ButtonBase组件使用或继承的,都分布在指定的component. 我们已经使用此行为通过将其交给控制来发送所to使用props您可以以相同的方式发送任何其他props。请注意,这对于都有明确记录LinkTabButtonBaseTab

感谢@josh-l 要求添加此内容。

太好了,谢谢!搞定了!但是,是的,也许用更多细节更新答案可以帮助其他人。无论哪种方式都赞成!
2021-04-21 16:41:32
您能否更具体地说明为“组件”和“到”api 传递的参数是什么?我正在查看材料 UI v1 api 选项卡文档,但没有显示其中任何一个?material-ui-1dab0.firebaseapp.com/api/tab
2021-04-29 16:41:32
对于大多数 mui 容器组件,您可以发送一个componentprop 以使其使用不同的 React 组件而不是默认组件。在这个例子中,我们让 Tab 渲染 react router Link 控件。在这种模式下, mui 组件会将任何额外的道具传递给该组件。由于 Link 需要一个to道具,我在 Tab 中传递了它。您会在 mui 中的某处发现这种行为。将尝试尽快更新我的答案。
2021-04-30 16:41:32

您现在可以这样做:

<Tabs onChange={this.changeTab} value={value}>
   <Tab value={0} label="first" containerElement={<Link to="/first"/>} />
   <Tab value={1} label="second" containerElement={<Link to="/second"/>}/>
   <Tab value={2} label="third" containerElement={<Link to="/third"/>} />
 </Tabs>
我试过的那些(对他们来说有道理)他们确实有
2021-04-23 16:41:32
甜的。但我注意到文档没有这么说。所有元素都支持containerElement吗?
2021-04-26 16:41:32
在撰写本文时,此技术似乎不适用于material-ui@next.
2021-05-14 16:41:32

你可以试试这个简单的方法

 <Tab label='Most popular ideas'  to='/myPath' component={Link} />
Error: React.Children.only expected to receive a single React element child.为我投掷
2021-04-22 16:41:32
这对我有用。但是,无论如何要删除“蓝色下划线”链接样式?
2021-04-24 16:41:32
没有抛出错误,但它对我不起作用。运行 4.11 核心用户界面
2021-05-02 16:41:32
这应该是最新的 material-ui 的正确答案 4+
2021-05-14 16:41:32
2020 年仍然是一个更简单的解决方案
2021-05-21 16:41:32

这是使用<Link />from material-ui 而不是直接使用<Link />or <NavLink />from react-router 来解决的。可以在此处的文档中找到相同的示例。

https://material-ui.com/components/links/

<Button />标记有分量的props来实现这一目标

<Button color="inherit" component={Link} to={"/logout"}>Logout</Button>

可以在此处找到对此的广泛讨论

https://github.com/mui-org/material-ui/issues/850

由于我们使用的是 TypeScript,因此我无法使用 @hazardous 解决方案。这就是我们为material-ui v1.0.0-beta.16实现路由的方式react-router 4.2.0我们拆分的原因this.props.history.location.pathname是因为我们需要访问/renewals/123例如。如果我们不这样做,我们将收到以下警告,并且不会将任何选项卡显示为活动状态:Warning: Material-UI: the value provided '/renewals/123' is invalid

带导入的完整代码:

import * as React from "react";
import * as ReactDOM from "react-dom";
import * as ReactRouter from "react-router";
import * as PropTypes from "prop-types";
import { Switch, Route, Redirect, Link  } from "react-router-dom";
import { Cases } from './../Cases';
import { SidePane } from './../SidePane';
import { withStyles, WithStyles } from 'material-ui/styles';
import Paper from 'material-ui/Paper';
import Tabs, { Tab } from 'material-ui/Tabs';
import { withRouter } from "react-router-dom";
import Badge from 'material-ui/Badge';
import Grid from 'material-ui/Grid';
import { Theme } from 'material-ui/styles';
import SimpleLineIcons from '../../Shared/SimpleLineIcons'

interface IState {
    userName: string;
}

interface IProps {
    history?: any
}

const styles = (theme: Theme) => ({
    root: theme.typography.display1,
    badge: {
        right: '-28px',
        color: theme.palette.common.white,
    },
    imageStyle:{
        float: 'left',
        height: '40px',
        paddingTop: '10px'
    },
    myAccount: {
        float: 'right'
    },
    topMenuAccount: {
        marginLeft: '0.5em',
        cursor: 'pointer'
    }
});

type WithStyleProps = 'root' | 'badge' | 'imageStyle' | 'myAccount' | 'topMenuAccount';

class Menu extends React.Component<IProps & WithStyles<WithStyleProps>, IState> {
    constructor(props: IProps & WithStyles<WithStyleProps>) {
        super(props);
        this.state = {
            userName: localStorage.userName ? 'userName ' + localStorage.userName : ""
        }
    }
    componentDidMount() {
        this.setState({ userName: localStorage.userName ? localStorage.userName : "" })
    }
    logout(event: any) {
        localStorage.removeItem('token');
        window.location.href = "/"
    }

    handleChange = (event: any, value: any) => {
        this.props.history.push(value);
    };

    render() {
        const classes = this.props.classes;
        let route = '/' + this.props.history.location.pathname.split('/')[1];
        return (
            <div>
                <Grid container spacing={24}>
                    <Grid item xs={12} className={classes.root}>
                        <img src="/Features/Client/Menu/logo.png" alt="Logo" className={classes.imageStyle} />
                        <div className={this.props.classes.myAccount}>
                        <span><span className={this.props.classes.topMenuAccount}>MY ACCOUNT</span><span className={classes.topMenuAccount}><SimpleLineIcons iconName={'user'} />&#x25BE;</span></span>
                            <span onClick={this.logout} className={classes.topMenuAccount}><SimpleLineIcons iconName={'logout'} /></span>
                        </div>
                    </Grid>
                    <Grid item xs={12} >
                        <div className="route-list">
                            <Tabs
                                value={route}
                                onChange={this.handleChange}
                                indicatorColor="primary"
                                textColor="primary"
                            >
                                <Tab label="Overview" value="/" />
                                <Tab label={<Badge classes={{ badge: classes.badge }} badgeContent={this.props.caseRenewalCount} color="primary">
                                    Renewals
                                   </Badge>} value="/renewals" />
                            </Tabs>
                        </div>
                    </Grid>
                </Grid>
            </div>
        );
    }
}
export default withStyles(styles)(withRouter(Menu))