Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Menu组件应该如何结合react-router Link组件? #1575

Closed
flicker85 opened this issue May 4, 2016 · 18 comments
Closed

Menu组件应该如何结合react-router Link组件? #1575

flicker85 opened this issue May 4, 2016 · 18 comments

Comments

@flicker85
Copy link

jsx

<Menu.Item key="1"><Link to="/page1">Page1</Link></Menu.Item>

生成的代码

<li class="ant-menu-item" role="menuitem" aria-selected="false" style="padding-left: 48px;">
  <a href="/page1">Page1</a>
</li>

点击padding-left:48px的空白处会选中菜单,但是不会触发Link to的事件,有什么好的处理方式么?

@benjycui
Copy link
Contributor

benjycui commented May 4, 2016

Duplicated: #1432

Please read FAQ and search issues before open an issue, THX!

It will be better if you read smart questions(提问的智慧).

@benjycui benjycui closed this as completed May 4, 2016
@flicker85
Copy link
Author

ok, 已解决~

import { browserHistory} from 'react-router';

export default class extends React.Component {
    linkTo(item) {
        browserHistory.push(item.key);
    }
    render() {
        return (
            <Menu mode="inline" theme="dark" defaultSelectedKeys={['page1']} onClick={this.linkTo}>
                <Menu.Item key="page1">Page1</Menu.Item>
                <Menu.Item key="page2">Page2</Menu.Item>
                <Menu.Item key="page3">Page3</Menu.Item>
            </Menu>
        );
    }
}

@ranchoX
Copy link

ranchoX commented Sep 3, 2016

@flicker85 这样实现不是那么完美,浏览器回退不会自动改变menu 的状态

@flicker85
Copy link
Author

flicker85 commented Nov 9, 2016

@ranchoX

export default class extends React.Component {
  constructor() {
    super();
    this.state = {
      selectedKeys: []
    }
  }

  static contextTypes = {
    router: React.PropTypes.object
  }

  componentWillReceiveProps() {
    this.setState({ selectedKeys: [this.context.router.location.pathname] });
  }

  componentDidMount() {
    this.setState({ selectedKeys: [this.context.router.location.pathname] });
  }

  linkTo(item) {
    this.context.router.push(item.key);
  }

  render() {
    return (
      <Menu mode="inline" theme="dark" defaultSelectedKeys={['page1']} selectedKeys={this.state.selectedKeys} onClick={this.linkTo}>
        <Menu.Item key="page1">Page1</Menu.Item>
        <Menu.Item key="page2">Page2</Menu.Item>
        <Menu.Item key="page3">Page3</Menu.Item>
      </Menu>
    );
  }
}

@truhangle
Copy link

@flicker85 如果这个有状态的菜单放到一个无状态的父级容器组件里面,this.context undefined怎么办?

@truhangle
Copy link

@flicker85 我直接把你这段代码拿到项目中,this,context是undefined

@truhangle
Copy link

最终解决方式

`import React, { PropTypes } from 'react';
import { Menu, Icon, Switch } from 'antd';
import { Link } from 'dva/router';

const LeftMenu = React.createClass({

getInitialState() {//初始化
return {
selectedKeys: []
};
},

contextTypes :{
router: React.PropTypes.object
},

componentWillReceiveProps() {
this.setState({ selectedKeys: [this.context.router.location.pathname] });
},

componentDidMount() {
this.setState({ selectedKeys: [this.context.router.location.pathname] });
},

linkTo(item) {
this.context.router.push(item.key);
},

render() {
return (
<Menu mode="inline" theme="dark" defaultSelectedKeys={['/role']} selectedKeys={this.state.selectedKeys} onClick={this.linkTo}>
<Menu.Item key="/role">角色管理</Menu.Item>
<Menu.Item key="/product">产品列表设置</Menu.Item>
<Menu.Item key="/document">上传资料设置</Menu.Item>

);
}
});

export default LeftMenu;
`

@chengzhenping
Copy link

最简单的方式
.ant-menu-item{
padding: 0 !important;
}

@Dodd2013
Copy link

Dodd2013 commented Jan 5, 2018

为什么不直接这样呢
`export default class extends Component {
contextTypes :{
router: PropTypes.object
},
linkTo(item) {
this.context.router.history.push(key);
}

render() {
return (
<Menu mode="inline" theme="dark" defaultSelectedKeys={['/page1']} selectedKeys={this.context.router.history.location.pathname]} onClick={this.linkTo}>
<Menu.Item key="/page1">Page1</Menu.Item>
<Menu.Item key="/page2">Page2</Menu.Item>
<Menu.Item key="/page3">Page3</Menu.Item>

);
}
}`

@saniagh
Copy link

saniagh commented Jan 8, 2018

This would be much more useful if it were in English.
The issue with the Menu not updating when the route changes is fixed with the code @flicker85 provided.
componentDidMount will make sure defaultSelectedKeys gets the current location so that when the page is first loaded the correct Menu Item is highlighted
componentWIllReceiveProps will provide the new location for the selectedKeys props of the Menu and update accordingly, even if you use a tag from React Router

@nadunindunil
Copy link

nadunindunil commented Feb 2, 2018

Hi I could find a solution this way using withRouter in react router

It's from here : https://stackoverflow.com/questions/41054657/react-routerantd-how-to-highlight-a-menu-item-when-press-back-forward-button

import React,{ Component } from 'react';
import { NavLink, withRouter } from 'react-router-dom';
import { Layout, Menu, Icon } from 'antd';
import PropTypes from 'prop-types';

const { Sider } = Layout;


class SideMenu extends Component{

  static propTypes = {
    location: PropTypes.object.isRequired
  }
  
  render() {
    const { location } = this.props;
    return (
        <Sider
        trigger={null}
        collapsible
        collapsed={this.props.collapsed}>

        <div className="logo" />
          <Menu theme="dark" mode="inline" defaultSelectedKeys={['/']} selectedKeys={[location.pathname]}>
            <Menu.Item key="/">
              <NavLink to="/">
                <Icon type="user" />
                <span>Home</span>
              </NavLink>
            </Menu.Item>
            <Menu.Item key="/notifications">
              <NavLink to="/notifications">
                 <Icon type="upload" />
                 <span>Notifications</span>
              </NavLink>
            </Menu.Item>
          </Menu>
        </Sider>
    )
  }
}

export default withRouter(SideMenu);

feel free to add any suggestions if you think I can improve this more.

@jacktang
Copy link

@nadunindunil how to use SideMenu class in App.js? Could you pls give some example?

@nadunindunil
Copy link

nadunindunil commented Feb 19, 2018

@jacktang

import React, { Component } from 'react';
import { Switch, Route } from 'react-router-dom';
import { Layout } from 'antd';

import HomePage from './home/HomePage';
import Navbar from './common/Navbar';
import NotificationPage from './notifications/notificationPage';
import SideMenu from './common/SideMenu';
import Header from './common/Header';

const { Content } = Layout;

class mainApp extends Component {
  state = {
    collapsed: false
  };
  toggle = () => {
    this.setState({
      collapsed: !this.state.collapsed
    });
  };
  render() {
    return (
      <Layout>
        <SideMenu collapsed={this.state.collapsed} />
        <Layout>
          <Navbar collapsed={this.state.collapsed} toggle={this.toggle} />
          <Content
            style={{
              margin: '24px 16px',
              padding: 24,
              background: '#fff',
              minHeight: '90vh'
            }}
          >
            <div>
              <Header />
              <Switch>
                <Route exact path="/" component={HomePage} />
                <Route path="/notifications" component={NotificationPage} />
              </Switch>
            </div>
          </Content>
        </Layout>
      </Layout>
    );
  }
}

export default mainApp;

app.js will be

import { Router } from 'react-router-dom';
import { Provider } from 'react-redux';
import React, { Component } from 'react';
import createBrowserHistory from 'history/createBrowserHistory';

import configureStore from './store/configureStore';
import initialState from './pages/initialState';
import MainApp from './pages/mainApp';

import './App.css';

const store = configureStore(initialState);
const customHistory = createBrowserHistory();

class App extends Component {
  render() {
    return (
      <Provider store={store}>
        <Router history={customHistory}>
          <MainApp />
        </Router>
      </Provider>
    );
  }
}

export default App;

I used mainApp.js to make it easier.
hope this will help you

@afc163 afc163 added this to the aDY milestone Feb 19, 2018
@Cleam
Copy link

Cleam commented Apr 26, 2018

Look at here

<MenuItem
  containerElement={<Link to="/profile" />} // Here!!!
  primaryText="Profile"
  leftIcon={
    <FontIcon className="material-icons">people</FontIcon>
  }
/>

@rohitmarneni
Copy link

@Cleam I think you are referring to material-ui since containerElement prop is not defined in antd for Menu.Item component.

@rex-ll
Copy link

rex-ll commented Apr 24, 2019

@chengzhenping

最简单的方式
.ant-menu-item{
padding: 0 !important;
}

这样没有解决回退时item的高亮问题

@Jiang-Xuan
Copy link
Contributor

Hi I could find a solution this way using withRouter in react router

It's from here : https://stackoverflow.com/questions/41054657/react-routerantd-how-to-highlight-a-menu-item-when-press-back-forward-button

import React,{ Component } from 'react';
import { NavLink, withRouter } from 'react-router-dom';
import { Layout, Menu, Icon } from 'antd';
import PropTypes from 'prop-types';

const { Sider } = Layout;


class SideMenu extends Component{

  static propTypes = {
    location: PropTypes.object.isRequired
  }
  
  render() {
    const { location } = this.props;
    return (
        <Sider
        trigger={null}
        collapsible
        collapsed={this.props.collapsed}>

        <div className="logo" />
          <Menu theme="dark" mode="inline" defaultSelectedKeys={['/']} selectedKeys={[location.pathname]}>
            <Menu.Item key="/">
              <NavLink to="/">
                <Icon type="user" />
                <span>Home</span>
              </NavLink>
            </Menu.Item>
            <Menu.Item key="/notifications">
              <NavLink to="/notifications">
                 <Icon type="upload" />
                 <span>Notifications</span>
              </NavLink>
            </Menu.Item>
          </Menu>
        </Sider>
    )
  }
}

export default withRouter(SideMenu);

feel free to add any suggestions if you think I can improve this more.

awesome, can use useLocation also.

@Mrrabbitan
Copy link

use hashmap could resolve problem of 'Router 'history' is declared here'.

winwu added a commit to winwu/lab-analytics-dashboard that referenced this issue Feb 2, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests