-
-
Notifications
You must be signed in to change notification settings - Fork 47.5k
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
how to use sider with react-router links ? #6576
Comments
Hello @xgqfrms-gildata, your issue has been closed because it does not conform to our issue requirements. Please use the Issue Helper to create an issue, thank you! |
I will just give up you! |
you can add Link in Menu.Item。
|
then there is no menu state change when click the brower's refresh or back button. |
Im not sure why @yunshuipiao has so many downvotes, his solution fixed my problem. I also came from #4853 and wasn't sure that Menu/Menu.Item could take any HOC. |
Thats works for me import React from "react";
import { NavLink } from "react-router-dom";
import { Layout, Menu } from "antd";
import { connect } from "react-redux";
import { logout } from "../../store/actions/auth";
const { Content, Sider } = Layout;
const SystemLayout = props => {
return (
<Layout
style={{
height: "-webkit-fill-available"
}}
>
<Layout>
<Sider width={200} style={{ background: "#fff" }} collapsible>
<Menu
activeKey={props.currentPath}
mode="inline"
selectedKeys={props.currentPath}
style={{ height: "100%", borderRight: 0 }}
>
<Menu.Item key="/dashboard">
<NavLink to="/dashboard" className="nav-text">
Dashboard
</NavLink>
</Menu.Item>
<Menu.Item key="/tenants">
<NavLink to="/tenants" className="nav-text">
Tenants
</NavLink>
</Menu.Item>
<Menu.Item key="/users">
<NavLink to="/users" className="nav-text">
Users
</NavLink>
</Menu.Item>
</Menu>
</Sider>
<Layout style={{ padding: "0 24px 24px" }}>
<Content
style={{
background: "#fff",
padding: 24,
margin: 0,
minHeight: 280
}}
>
{props.children}
</Content>
</Layout>
</Layout>
</Layout>
);
};
const mapStateToProps = state => {
return {
currentPath: state.routing.location.pathname
};
};
const mapDispatchToProps = dispatch => {
return {
logout: () => dispatch(logout(dispatch))
};
};
export default connect(mapStateToProps, mapDispatchToProps)(SystemLayout); |
I use this with latest version of Next and AntD
|
check this Example |
You can use the selectedKeys from antd's menu and match the location.pathname property of react-router@4 to the menu.item key import React from 'react';
import { Link, withRouter } from 'react-router-dom';
import { Menu } from 'antd';
const Linkmenu = withRouter(props => {
const { location } = props;
return (
<Menu mode="inline" selectedKeys={[location.pathname]}>
<Menu.Item key="/">
<Link to="/">Home </Link>
</Menu.Item>
<Menu.Item key="/about">
<Link to="/about">About</Link>
</Menu.Item>
</Menu>
);
});
export default Linkmenu; |
@Dennis-Smurf great solution |
anyone know a good way to default expand the submenu that contains the current active item? eg: <Menu mode="inline" selectedKeys={[location.pathname]}>
<SubMenu key="sub1" title={<span><Icon type="mail" /><span>One</span></span>}>
<Menu.Item>
<Link to="/foo1">Foo 1</Link>
</Menu.Item>
<Menu.Item>
<Link to="/bar1">Bar 1</Link>
</Menu.Item>
</SubMenu>
<SubMenu key="sub2" title={<span><Icon type="desktop" /><span>Two</span></span>}>
<Menu.Item>
<Link to="/foo2">Foo 2</Link>
</Menu.Item>
<Menu.Item>
<Link to="/bar2">Bar 2</Link>
</Menu.Item>
</SubMenu>
</Menu> for |
@Dennis-Smurf Thanks. |
@Dennis-Smurf What if the route key contains an argument? For example |
Ok, I came up with a solution that uses react-router's Here's a full example:
|
I am using @Dennis-Smurf's solution, and it's technically working, but the page wont navigate or load the new component until I move the mouse off of the nav item I clicked on. Anyone know why that could be?
|
Using one of the solutions above but with @reach/router you can do the following import {Location} from '@reach/router'
const navButtons = [
{
path: '/home',
name: 'Home'
}
]
export default function DashboardSideNav({collapsed}) {
return (
<Location>
{({location}) => {
return (
<Sider trigger={null} collapsible collapsed={collapsed}>
<Menu
theme="dark"
mode="inline"
defaultSelectedKeys={[location.pathname]}
>
{navButtons.map((button, index) => (
<Menu.Item key={button.path}>
<ExactNavLink to={button.path}>
<Icon type={button.icon} />
<span>{button.name}</span>
</ExactNavLink>
</Menu.Item>
))}
</Menu>
</Sider>
)
}}
</Location>
)
} |
i use this and work. import React, { Component } from 'react';
import { Link, withRouter } from 'react-router-dom';
import {
Layout, Menu, Icon
} from 'antd';
const {Sider} = Layout;
const SubMenu = Menu.SubMenu;
class Navigation extends Component {
state = {
collapsed: false,
current: '/home',
};
onCollapse = (collapsed) => {
this.setState({ collapsed });
}
render() {
const { location } = this.props
return (
<Sider collapsible collapsed={this.state.collapsed} onCollapse={this.onCollapse}>
<div className="app-logo" />
<Menu theme="dark" mode="inline" inlineCollapsed={true} selectedKeys={[location.pathname]}>
<Menu.Item key="/home">
<Link to="/home">
<Icon type="pie-chart"/><span>Dashboard</span>
</Link>
</Menu.Item>
<SubMenu key="sub-master" title={<span><Icon type="plus-square"/><span>Master</span></span>}>
<Menu.Item key="/server">
<Link to="/server">Server</Link>
</Menu.Item>
<Menu.Item key="/company">
<Link to="/company">Company</Link>
</Menu.Item>
<Menu.Item key="/application">
<Link to="/application">Application</Link>
</Menu.Item>
<Menu.Item key="/group">
<Link to="/group">Group</Link>
</Menu.Item>
</SubMenu>
</Menu>
</Sider>
);
}
}
export default withRouter(Navigation) |
If anyone's interested, here's a complete example. It even opens any submenus and highlights the nested submenu correctly on page load and works with deeply nested subroutes by also including the "root" route as one of the import React from 'react'
import {observer, inject} from 'mobx-react'
import {NavLink, withRouter} from 'react-router-dom'
import {Layout, Menu, Icon} from 'ui'
import {Logo} from 'components'
import {Plane as PlaneIcon, Users as UsersIcon} from 'ui/icons'
const {Sider} = Layout
const Item = ({to, children, exact = false, ...props}) => (
<Menu.Item {...props}>
<NavLink class="nav-text" activeClassName="active" to={to} exact={exact}>
{children}
</NavLink>
</Menu.Item>
)
const items = [
{
title: 'Dashboard',
icon: 'appstore-o',
path: '/',
exact: true
},
{
title: 'Customize Icon',
icon: {component: PlaneIcon, style: {width: 19}},
path: '/test'
},
{
title: 'Submenu Example',
icon: 'layout',
path: '/submenu',
submenu: [
{
title: 'Submenu',
path: '/submenu/one'
},
{
title: 'Thing',
path: '/submenu/thing'
},
{
title: 'Optimizer',
path: '/submenu/optimize'
}
]
},
{
title: 'Admin',
icon: 'reconciliation',
path: '/admin/company'
}
]
const renderMenuItemChildren = ({icon, title}) => (
<>
{icon && <Icon type={icon} {...icon} />}
<span data-testid={title.toLowerCase + '-nav'}>{title}</span>
</>
)
const renderMenuItem = item => {
return item.submenu ? (
<Menu.SubMenu key={item.path} title={renderMenuItemChildren(item)}>
{item.submenu.map(renderMenuItem)}
</Menu.SubMenu>
) : (
<Item key={item.path} to={item.path} exact={item.exact}>
{item.children ? item.children : renderMenuItemChildren(item)}
</Item>
)
}
@inject('appstore')
@withRouter
@observer
export default class Navigation extends React.Component {
render() {
const {appstore, location} = this.props
const root = '/' + location.pathname.split('/')[1]
return (
<Sider
theme={appstore.ui.theme}
collapsible
collapsed={appstore.ui.siderCollapsed}
onCollapse={collapsed => (appstore.ui.siderCollapsed = collapsed)}>
<Menu
theme={appstore.ui.theme}
mode="inline"
style={{top: 50}}
defaultOpenKeys={[root]}
selectedKeys={[root, location.pathname]}>
{items.map(renderMenuItem)}
</Menu>
</Sider>
)
}
}
|
...
... Then if you refresh the page - the current route stay selected and when you go to another route - it will deselect sider menu. But maybe somebody have more correct and elegant solution? |
class Sidemenu extends Component {
state = { selectedRoute: "home" }
setActiveRoute() {
switch (this.props.history.location.pathname) {
case "/someRoute":
this.setState({ selectedRoute: "someRoute" })
break;
case "/":
this.setState({ selectedRoute: "home" });
break;
default:
break;
}
}
componentDidMount() {
// Set initial route on page load
this.setActiveRoute();
this.props.history.listen(() => {
// Listen for route change and set selected route key for sidebar
this.setActiveRoute();
});
}
render() {
return (
<Menu
theme="dark"
mode="inline"
selectedKeys={[this.state.selectedRoute]}
style={{ height: '100%', borderRight: 0 }}
>
<Menu.Item key="home" />
</Menu>
)
}
} This is one way to do it. |
great solution @Dennis-Smurf this should be in the documentation of Ant.design |
@Dennis-Smurf , perfect solution!!thx |
Could get simple as that
|
try this import React, { useState, useEffect } from 'react'
import { Switch, Route, Link, Redirect, useHistory } from 'react-router-dom'
import Home from './Home'
import Setting from './Setting'
import Group1Page1 from './group1/Page1'
import Group1Page2 from './group1/Page2'
import '../assets/css/layout.sass'
import { Layout, Menu } from 'antd'
import {
HomeOutlined,
AuditOutlined,
PayCircleOutlined,
UserOutlined,
} from '@ant-design/icons'
const { Header, Content, Footer, Sider } = Layout
const { SubMenu } = Menu
export default props => {
const history = useHistory()
const MenuList = [
{ title: '首页', icon: <HomeOutlined />, path: '/', },
{
title: 'group1', icon: <AuditOutlined />,
children: [
{ title: 'page1', path: '/group1/page1', },
{ title: 'page2', path: '/group1/page2', },
]
},
{ title: '设置', icon: <PayCircleOutlined />, path: '/setting', },
]
const currPath = history.location.pathname
const [title, setTitle] = useState(null)
function menuChange(info) {
if (currPath === info.path) return
history.push(info.path)
}
useEffect(() => {
for (let item of MenuList) {
if (!item.children) {
if (item.path === currPath) setTitle(item.title)
} else {
for (let child of item.children) {
if (child.path === currPath) setTitle(child.title)
}
}
}
}, [currPath])
return (
<Layout>
<Sider className='layout-sider' >
<div className="layout-logo">QMPC SYSTEM</div>
<Menu theme='dark' mode="inline" defaultOpenKeys={['group1']} selectedKeys={[title]}>
{
MenuList.map(menu => {
if (!menu.children) {
return <Menu.Item key={menu.title} icon={menu.icon} onClick={() => { menuChange(menu) }}>{menu.title}</Menu.Item>
} else {
return (
<SubMenu key={menu.title} icon={menu.icon} title={menu.title}>
{
menu.children.map(child => {
return <Menu.Item key={child.title} onClick={() => { menuChange(child) }}>{child.title}</Menu.Item>
})
}
</SubMenu>
)
}
})
}
</Menu>
</Sider>
<Layout className="layout-container">
<Header className="layout-header">
<span className="title">{title}</span>
<div className='account-cover'>
<UserOutlined className='icon-user' />
<span className="account">account</span>
<Link to='/sign-in'>登出</Link>
</div>
</Header>
<Content className='layout-content'>
<Switch>
<Route exact path='/' component={Home} />
<Route exact path='/group1/page1' component={Group1Page1} />
<Route exact path='/group1/page2' component={Group1Page2} />
<Route exact path='/Setting' component={Setting} />
<Redirect to='/404' />
</Switch>
</Content>
<Footer className='layout-footer'>XXX System ©2020 Created by XXX Tech</Footer>
</Layout>
</Layout>
)
} |
he is getting the down vote because the highlighting of different menu options can't be resolved with this as Link gets refreshed whenever clicked and the default key gets highligted |
Hi everyone! This is what I've discovered:
As I understood, menu should have wide width in order not to be hidden in "more" like button. |
Hi |
component: import { useMemo } from 'react';
import { matchPath, NavLink, To } from 'react-router-dom';
import { Menu } from 'antd';
export type MenuItem = {
key?: string;
path: string;
pathMatchPattern?: string;
caption: string;
};
export type MenuProps = {
location: any;
items: MenuItem[];
};
const TopMenu: React.FC<MenuProps> = ({ items, location }) => {
const selectedKeys = useMemo(
() =>
items.reduce<string[]>((acc, item) => {
if (matchPath(item.pathMatchPattern || item.path, location.pathname)) {
acc.push(item.key || item.path);
}
return acc;
}, []),
[items, location]
);
return (
<Menu mode="horizontal" selectedKeys={selectedKeys} theme="dark">
{items.map((item) => (
<Menu.Item key={item.key || item.path}>
<NavLink to={item.path}>{item.caption}</NavLink>
</Menu.Item>
))}
</Menu>
);
};
export default TopMenu; usage: const location = useLocation();
return (
<TopMenu
items={[
{
path: '/',
caption: 'Main',
},
{
path: '/profile',
caption: 'Profile',
},
{
path: '/orders',
caption: 'Orders',
},
{
path: '/logout',
caption: 'Logout',
},
]}
location={location}
/>
); |
Create a link and work with the collapse Active link set Important use
|
https://ant.design/components/menu-cn/#components-menu-demo-sider-current
how to use
sider
component with react-routerlinks
?I just can't understand why it doesn't works!
The text was updated successfully, but these errors were encountered: