Skip to content

Instantly share code, notes, and snippets.

@VesperDev
Last active May 12, 2024 05:08
Show Gist options
  • Save VesperDev/e233115469a6c53bb96443f66385aa22 to your computer and use it in GitHub Desktop.
Save VesperDev/e233115469a6c53bb96443f66385aa22 to your computer and use it in GitHub Desktop.
Sider menu + ant-design + react-router-dom
import React, { Component } from 'react';
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
import { Layout, Menu, Icon } from 'antd';
import Dashboard from './containers/Dashboard/Dashboard';
import Meseros from './containers/Meseros/Meseros';
const { Header, Content, Footer, Sider } = Layout;
const SubMenu = Menu.SubMenu;
class RouterApp extends Component {
state = {
collapsed: false,
};
onCollapse = (collapsed) => {
this.setState({ collapsed });
}
toggle = () => {
this.setState({
collapsed: !this.state.collapsed,
});
}
render() {
return (
<Router>
<Layout style={{ minHeight: '100vh' }}>
<Sider
collapsible
collapsed={this.state.collapsed}
onCollapse={this.onCollapse}>
<div className="logo" />
<Menu theme="dark" defaultSelectedKeys={['1']} mode="inline">
<Menu.Item key="1">
<Icon type="pie-chart" />
<span>Deshboard</span>
<Link to="/" />
</Menu.Item>
<Menu.Item key="2">
<Icon type="desktop" />
<span>Meseros</span>
<Link to="/meseros" />
</Menu.Item>
</Menu>
</Sider>
<Layout>
<Header style={{ background: '#fff', padding: 0, paddingLeft: 16 }}>
<Icon
className="trigger"
type={this.state.collapsed ? 'menu-unfold' : 'menu-fold'}
style={{ cursor: 'pointer' }}
onClick={this.toggle}
/>
</Header>
<Content style={{ margin: '24px 16px', padding: 24, background: '#fff', minHeight: 280 }}>
<Route exact path="/" component={Dashboard} />
<Route path="/meseros" component={Meseros} />
</Content>
<Footer style={{ textAlign: 'center' }}>
Ant Design ©2016 Created by Ant UED
</Footer>
</Layout>
</Layout>
</Router>
);
}
}
export default RouterApp;
@zcmgyu
Copy link

zcmgyu commented May 14, 2019

When you access /meseros directly, selected icon didn't change

@2marcous
Copy link

2marcous commented Jul 2, 2019

Hello, this great exmaple ,

@namcoder
Copy link

Nice for use Link in the Menu Item. Thank you ;)

@allenlongbaobao
Copy link

when you click the menu item, selected status not change, it not works for me.

@doseeing
Copy link

doseeing commented Jan 22, 2020

when you click the menu item, selected status not change, it not works for me.

<Switch> tag is missing from Route, try to add <Switch> tag around <Route>

EDIT: not the reason.

@fasmat
Copy link

fasmat commented Jan 25, 2020

when you click the menu item, selected status not change, it not works for me.

<Switch> tag is missing from Route, try to add <Switch> tag around <Route>

This doesn't solve the issue, Switch just ensures that only one Route will be rendered.

@xinghul
Copy link

xinghul commented Jan 26, 2020

this will not work if you change route programmatically.

@doseeing
Copy link

doseeing commented Feb 4, 2020

when you click the menu item, selected status not change, it not works for me.

<Switch> tag is missing from Route, try to add <Switch> tag around <Route>

This doesn't solve the issue, Switch just ensures that only one Route will be rendered.

Yes, you're right. It should be some error.
BTW, there's a working example using repo code:

https://codesandbox.io/embed/fervent-thunder-egyk1?fontsize=14&hidenavigation=1&theme=dark

@dooleyb1
Copy link

Is there any way to force the Sider tab to be selected when navigating to the selected route? Mine is rendering the correct element but the Sider tab is not being selected.

@cjmling
Copy link

cjmling commented Apr 8, 2020

Note above example is based on ant v3 .

In v4 icon have moved have moved, https://ant.design/components/icon/

@cardotrejos
Copy link

I was looking this example! Thanks!

@cdclaw
Copy link

cdclaw commented Apr 20, 2020

this will not work if you change route programmatically.

Any idea how to solve this problem?

@aneopsy
Copy link

aneopsy commented Apr 21, 2020

If you go directly to "/meseros" or refresh the page, the menu key is wrong because it's set to 1 by default. I'm trying to find one way.

Edit: The best way I found is to use withRouter to pass location as a props and use "selectedKeys={[props.location.pathname]}" in Menu when keys are the subpath ex: key="/"

@mahsa-kh
Copy link

Thanks. Helped me a lot!

@JustGAST
Copy link

@aneopsy, thanks for the tip!
I've done more complex routing selection like this.
I have routes: /admin/course/list, /admin/course/edit, /admin/user/list, /admin/user/edit
And match them in selectedRoute function:

const selectedRoute = () => [
    props.location.pathname.replace(/^(\/admin\/\w+)\/.*/, '$1')
];

<Menu
    mode="inline"
    defaultSelectedKeys={['1']}
    defaultOpenKeys={['sub1']}
    style={{ height: '100%', borderRight: 0 }}
    selectedKeys={selectedRoute()}
>
    <SubMenu key="sub1" icon={<LaptopOutlined />} title="Редактирование" >
        <Menu.Item key={`/admin/course`}>
            <Link to={`/admin/course/list`}>Курсы</Link>
        </Menu.Item>
        <Menu.Item key={`/admin/user`}>
            <Link to={`/admin/user/list`}>Пользователи</Link>
        </Menu.Item>
    </SubMenu>
</Menu>                    

@PubuduWanigasekara
Copy link

This is not connected in key

@yogithesymbian
Copy link

yogithesymbian commented Sep 21, 2020

u save my life , thanks brother @VesperDev

          {items.map((item, idx) => (
            <Menu
              theme={this.state.theme}
              onClick={this.handleClick}
              defaultOpenKeys={["sub1"]}
              selectedKeys={[this.state.current]}
              mode="inline"
            >
              <Menu.Item key={idx} tag={RouteNavLink} to={item.to}>
                <Link to={item.to} />
                {item.htmlBefore && (
                  <div
                    className="d-inline-block item-icon-wrapper"
                    dangerouslySetInnerHTML={{ __html: item.htmlBefore }}
                  />
                )}
                {item.title && <span>{item.title}</span>}
                {item.htmlAfter && (
                  <div
                    className="d-inline-block item-icon-wrapper"
                    dangerouslySetInnerHTML={{ __html: item.htmlAfter }}
                  />
                )}
              </Menu.Item>
            </Menu>
          ))}

@cosacak
Copy link

cosacak commented Sep 25, 2020

thanks

@MounsifChr
Copy link

when you click the menu item, the selected status not change, it not works for me.

Use a state where you keep the selected MenuItem "key" attr and write a function to set it whenever you click a MenuItem component.

pass the stored state to the "selectedKeys" attr on Menu component.

@fernandolucchesi
Copy link

fernandolucchesi commented Feb 19, 2021

Leaving my 2 cents, I managed to fix it using the useLocation hook.
Also had to use the path as key for the items, hope it helps someone. :)

import React from 'react';

import { Menu } from 'antd';
import { Link, useLocation } from 'react-router-dom';

const menuItems = [
  {
    name: 'My menu item',
    link: '/my-first-route',
  },
  {
    name: 'My second menu item',
    link: '/my-second-route',
  },
];

export function Menu() {
  const location = useLocation();

  return (
    <Menu selectedKeys={[location.pathname]}>
      {menuItems.map((item) => (
        <Menu.Item key={item.link}>
          <Link to={item.link}>{item.name}</Link>
        </Menu.Item>
      ))}
    </Menu>
  );
}

@Prabhakarkmr0
Copy link

thank you so much this is what I have been looking for

@ingeniousambivert
Copy link

ingeniousambivert commented Mar 24, 2021

@xinghul and @cdclaw did either one of you figure out how to fix it? I am also stuck here.

EDIT: I fixed the problem. Take a look at this repo.

@lghimfus
Copy link

@himanshu2454
Copy link

So I want to implement something like a Step layout, so only after menu in the sider are visited and the form there is validated should the user be allowed to move to another submenu.

image

issue is how to I restrict routes as well as per availability of submenus ??

@tekxau
Copy link

tekxau commented Mar 25, 2022

So helpful!

@haedoang
Copy link

당신은 1004

@joeydqyuan
Copy link

Leaving my 2 cents, I managed to fix it using the useLocation hook. Also had to use the path as key for the items, hope it helps someone. :)

import React from 'react';

import { Menu } from 'antd';
import { Link, useLocation } from 'react-router-dom';

const menuItems = [
  {
    name: 'My menu item',
    link: '/my-first-route',
  },
  {
    name: 'My second menu item',
    link: '/my-second-route',
  },
];

export function Menu() {
  const location = useLocation();

  return (
    <Menu selectedKeys={[location.pathname]}>
      {menuItems.map((item) => (
        <Menu.Item key={item.link}>
          <Link to={item.link}>{item.name}</Link>
        </Menu.Item>
      ))}
    </Menu>
  );
}

thanks a lot

@amed
Copy link

amed commented Jul 18, 2022

The use of nested components is deprecated and will be removed later.

https://ant.design/components/menu/#Usage-upgrade-after-4.20.0

@donev-stan
Copy link

donev-stan commented Aug 3, 2022

warning.js:6 Warning: [antd: Menu] children will be removed in next major version. Please use items instead.

How do I link to a component using items?

@harunkara
Copy link

Hello, I am using history.push to reach some pages after clicking menu items. But the titles of these pages are not in the menu. After using history.push() I send [] into SeleckedKey(). But when I click on one of the menu items that have a submenu on the pages I go to with history.push, it does not open the submenus. This situation is fixed when clicking on a second and different submenu item. I am using vertical as mode and I am getting this error only in mobile view. It works when I make it inline, but I don't want it to be inline as a view. I will be glad if you can help....

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment