can we use routes multiple times inside browser router? - react-router

Can we use multiple times inside the . I have with some options ,only these 2 routes should be placed in row and column view
App.js
import useRoutes from "./useRoutes";
export default App=()=>{
return(
<BrowserRouter>
{ <div className='row'>
<div className= 'col'>SideBar</div>
<div className= 'col'>{Routes}</div>
</div>} /*--displays only when user logged in,user menu --*/
<Routes />
</BrowserRouter>
)
}
Routes.js
import { useRoutes } from "react-router-dom";
function Routes() {
let element = useRoutes([
{
path: "/",
element: <Dashboard />,
},
{
path: "tasks",
element: <DashboardTasks /> },
},
{ path: "team",
element: <AboutPage /> },
]);
return element;
}
SideBar.js
export default SideBar=()=>{
return(
<ul>
<li>AboutPage</li>
<li>DashboardTasks</li>
</ul>
)
}
How to implement it ,how to show the routes in half side only in sidebar

Related

React won't render my components using router

I am very new to react and trying to work on my first website.
I have tried to seek my problem online, I've encountered similar questions to mine but could not figure out my exact problem.
My layout of components are in a scroll down style (portfolio), when I try route for example to my contact component it wont render unless I refresh my page. also instead of scrolling down to component it will pop up at the top .(Hope I am clear)
My App Function
import { useState } from 'react';
import { BrowserRouter, Route, Switch } from 'react-router-dom';
import './App.css';
import Contact from './Components/Contact/Contact';
import Form from './Components/FormArea/Form/form';
import Introdoction from './Components/Introdoction/Introdoction';
import NavBar from './Components/NavBar/NavBar';
import NavigationBar from './Components/NavigationBarHeader/NavigationBar/NavigationBar';
import Portfolio from './Components/Portfolio/Portfolio';
import Routing from './Components/Routing/Routing';
import Skills from './Components/Skills/Skills';
function App() {
return (
<BrowserRouter>
<Switch>
<div className="App">
<NavigationBar/>
<section className="section">
<Route path="/contact" component={Contact} exact/>
<Introdoction/>
<Portfolio/>
<Skills/>
{/* <Contact/> */}
<Form/>
</section>
</div>
</Switch>
</BrowserRouter>
);
}
export default App;
I am trying to configure "Contact" component for this example.
My Menu/Navbar Component
import { Component, MouseEventHandler } from "react";
import {MenuItems} from "../MenuItems/MenuItems";
import "./NavigationBar.css";
import icon from '../../../Assets/icon.png'
import {Button} from "../Button/Button";
import { NavLink, Redirect, Route, Switch, useHistory } from "react-router-dom";
import Contact from "../../Contact/Contact";
class NavigationBar extends Component {
state = {clicked : false}
handleClick = () => {
this.setState ( { clicked: !this.state.clicked } );
};
public render(): JSX.Element {
return (
<nav className="NavbarItems ">
<img className="navbar-logo"src={icon } />
<div className="menu-icon" onClick={this.handleClick}>
<i className={this.state.clicked ? 'fas fa-times' : 'fas times'}></i>
</div>
<ul className={this.state.clicked ? 'nav-menu active' : 'nav-menu'}>
{MenuItems.map((item,index) => {
return (
<li key={index}>
<NavLink to={item.url} className={item.cName} >{item.title} </NavLink>
</li>
)
})}
</ul>
<Button>Sign up</Button>
</nav>
);
}
}
export default NavigationBar;
ItemMenu Component
import { NavLink } from "react-router-dom";
import "./MenuItems.css";
export const MenuItems = [
{
title: 'Home',
url: '/Home',
cName: 'nav-links'
},
{
title: 'Introduction',
url: '/introduction',
cName: 'nav-links'
},
{
title: 'Skills',
url: '/skills',
cName: 'nav-links'
},
{
title: 'Projects',
url: '/projects',
cName: 'nav-links'
},
{
title: 'Contact',
url: '/contact',
cName: 'nav-links'
},
];
I could add more information if needed. I hope my question is clear on what my problem is.
Thanks.
If I understood your question correctly, you want one single page, with everything below each other, and when you press a link, it scrolls you down to that place. In that case I would use:
<Contact id="contact" />
react-router creates new sub pages, which you don't want (if I understood you correctly)

Gatsby conditional className based on frontmatter

I'm trying to add a className of split to my header, based on the page template as defined in the frontmatter of a page. I've got a page template called split and want the header to have that class on pages that are utilizing the template. Here are my templates:
layout.js
import React from 'react'
import PropTypes from 'prop-types'
import Helmet from 'react-helmet'
import { StaticQuery, graphql } from 'gatsby'
import Header from './header'
import Footer from './footer'
import '../css/main.scss'
import favicon from './favicon.png'
const Layout = ({ children, frontmatter }) => (
<StaticQuery
query={graphql`
query PageInfoQuery {
site {
siteMetadata {
title
footer
}
}
markdownRemark {
frontmatter {
template
}
}
}
`}
render={data => (
<>
<Helmet
title={data.site.siteMetadata.title}
meta={[
{ name: 'description', content: 'Sample' },
{ name: 'keywords', content: 'sample, something' },
]}
link={[
{
rel: 'shortcut icon',
type: 'image/png',
href: `${favicon}`,
},
]}
>
<html lang="en" />
</Helmet>
<Header siteTitle={data.site.siteMetadata.title} frontmatter={data.markdownRemark.frontmatter}/>
{children}
<Footer footer={data.site.siteMetadata.footer} />
</>
)}
/>
)
Layout.propTypes = {
children: PropTypes.node.isRequired,
}
export default Layout
header.js
import PropTypes from 'prop-types'
import React from 'react'
import Navbar from './navbar'
const Header = ({ siteTitle, frontmatter }) => (
<header className={ frontmatter.template === 'split' ? 'header split' : 'header' }>
<section className="navigation">
<Navbar siteTitle={siteTitle} />
</section>
</header>
)
Header.propTypes = {
siteTitle: PropTypes.string,
}
Header.defaultProps = {
siteTitle: '',
}
export default Header
I know that I've got the data.markdownRemark.frontmatter working correctly, as in my template split.js I'm able to display the template name dynamically in the hero element, using {post.frontmatter.template}. In the interest of being thorough I'll include that as well.
split.js
import React from 'react'
import Helmet from 'react-helmet'
// eslint-disable-next-line
import { Link, graphql } from 'gatsby'
import Layout from '../components/layout'
// import blocks
import Feature from '../components/blocks/feature'
import Hero from '../components/blocks/hero'
class BlocksTemplate extends React.Component {
render() {
const post = this.props.data.markdownRemark
const siteTitle = this.props.data.site.siteMetadata.title
const siteDescription = post.excerpt
const heroImage = post.frontmatter.hero_image.childImageSharp.fixed.src
return (
<Layout location={this.props.location} title={siteTitle}>
<Helmet
htmlAttribute={{ lang: 'en' }}
meta={[{ name: 'description', content: siteDescription }]}
title={`${post.frontmatter.title} • ${siteTitle}`}
/>
<section className="hero" style={{ backgroundImage: `url(${heroImage})` }}>
<h4 className="name">
<Link to="/">
{this.props.siteTitle}
{post.frontmatter.template}
</Link>
</h4>
</section>
{post.frontmatter.blocks.map(block => {
switch (block.component) {
case 'feature':
return <Feature block={block} />
case 'hero':
return <Hero block={block} />
default:
return ''
}
})}
</Layout>
)
}
}
export default BlocksTemplate
export const pageQuery = graphql`
query SplitPageBySlug($slug: String!) {
site {
siteMetadata {
title
}
}
markdownRemark(fields: { slug: { eq: $slug } }) {
id
excerpt
html
frontmatter {
template
title
hero_image {
childImageSharp {
fixed(width: 1500) {
src
}
}
}
blocks {
component
image {
childImageSharp {
fixed(width: 1500) {
src
}
}
}
}
}
}
}
`
Here is the header markup that is being rendered; in essence the split class is never being added.
<header class="header">
<section class="navigation">
<nav class="nav" role="navigation">
<div class="branding">
<h6 class="name">Jesse Winton</h6>
</div>
Home
<a aria-current="page" class="" href="/about-the-demo">What is this?</a>
About Gatsby
Blog
</nav>
</section>
</header>
I'm fairly new to Gatsby, so any help would be very much appreciated! Thank you!
In layout.js, you are passing frontmatter={data.markdownRemark.frontmatter} to the header from the query above it in layout.js. This is a staticQuery which will always return the same data.
I see you are querying for the correct data in the pageQuery in split.js, but this data is not passed along to the layout in split.js:
<Layout location={this.props.location} title={siteTitle}>
One way to fix this is to pass the template name to the layout props, just like you are already doing with location and title attributes.
Another way would be using the gatsby-plugin-layout plugin which return the old behavior from V1 Gatsby for the Layout component, adding a layout wrapper to every component. Then you could the pageContext to the split component directly.

How to create dynamic routes with react-router-dom?

I learn react and know, how to create static routes, but can't figure out with dynamic ones. Maybe someone can explain, I'll be very grateful. Let there be two components, one for rendering routes, and another as a template of a route. Maybe something wrong in the code, but hope You understand..
Here is the component to render routes:
import React, { Component } from 'react';
import axios from 'axios';
import Hero from './Hero';
class Heroes extends Component {
constructor(props) {
super(props);
this.state = {
heroes: [],
loading: true,
error: false,
};
}
componentDidMount() {
axios.get('http://localhost:5555/heroes')
.then(res => {
const heroes = res.data;
this.setState({ heroes, loading: false });
})
.catch(err => { // log request error and prevent access to undefined state
this.setState({ loading: false, error: true });
console.error(err);
})
}
render() {
if (this.state.loading) {
return (
<div>
<p> Loading... </p>
</div>
)
}
if (this.state.error || !this.state.heroes) {
return (
<div>
<p> An error occured </p>
</div>
)
}
return (
<div>
<BrowserRouter>
//what should be here?
</BrowserRouter>
</div>
);
}
}
export default Heroes;
The requested JSON looks like this:
const heroes = [
{
"id": 0,
"name": "John Smith",
"speciality": "Wizard"
},
{
"id": 1,
"name": "Crag Hack",
"speciality": "Viking"
},
{
"id": 2,
"name": "Silvio",
"speciality": "Warrior"
}
];
The route component (maybe there should be props, but how to do it in the right way):
import React, { Component } from 'react';
class Hero extends Component {
render() {
return (
<div>
//what should be here?
</div>
);
}
}
export default Hero;
I need something like this in browser, and every route url should be differentiaie by it's id (heroes/1, heroes/2 ...):
John Smith
Crag Hack
Silvio
Each of them:
John Smith.
Wizard.
and so on...
Many thanks for any help!)
Use Link to dynamically generate a list of routes.
Use : to indicate url params, :id in the case
Use the match object passed as props to the rendered route component to access the url params. this.props.match.params.id
<BrowserRouter>
/* Links */
{heroes.map(hero => (<Link to={'heroes/' + hero.id} />)}
/* Component */
<Route path="heroes/:id" component={Hero} />
</BrowserRouter>
class Hero extends Component {
render() {
return (
<div>
{this.props.match.params.id}
</div>
);
}
}
Update so this works for React Router v6:
React Router v6 brought some changes to the general syntax:
Before: <Route path="heroes/:id" component={Hero} />
Now: <Route path="heroes/:id" element={<Hero />} />
You can't access params like with this.props.match anymore:
Before: this.props.match.params.id
Now: import {useParams} from "react-router-dom";
const {id} = useParams();
You can now just use id as any other variable.
To do this you simply add a colon before the url part that should be dynamic. Example:
<BrowserRouter>
{/* Dynamic Component */}
<Route path="heroes/:id" component={Hero} />
</BrowserRouter>
Also you can use the useParams hook from react-router-dom to get the dynamic value for use in the page created dynamically. Example:
import { useParams } from "react-router-dom";
const Hero = () => {
const params = useParams();
// params.id => dynamic value defined as id in route
// e.g '/heroes/1234' -> params.id equals 1234
return (...)
}

React router only working with Link to, not with URL or on refresh

Not sure what is happening here. I have set up my routing and when I go to my first page localhost:8080/ the first route renders as expected. However if I enter into the url in localhost:8080/store the expected route fails and I receive a 404 cannot find (doesnt even fallback to my not found component).
However if I set up a Link to and click the link it will render my store route as expected.
Shouldn't /store render out my StorePicker component regardless if its entered into the URL or selected via a Link to element?
App.js
import React, { Component } from 'react';
import ReactDOM, { render } from 'react-dom';
import { BrowserRouter as Router, Route, Link, Switch } from 'react-router-dom';
//Components
import StorePicker from './components/StorePicker.js';
import Main from './components/Main';
import NotFound from './components/NotFound';
const Routes = () => {
return (
<Router>
<div>
<Link to="/store">Store</Link>
<Switch>
<Route path="/" exact component={StorePicker} />
<Route path="/store" component={Main} />
<Route component={NotFound} />
</Switch>
</div>
</Router>
)
}
render(<Routes />, document.querySelector('#container'));
Assuming you're using Webpack. If so, adding a few things to your webpack config should solve the issue. Specifically, output.publicPath = '/' and devServer.historyApiFallback = true.
var path = require('path');
var HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './app/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'index_bundle.js',
publicPath: '/'
},
module: {
rules: [
{ test: /\.(js)$/, use: 'babel-loader' },
{ test: /\.css$/, use: [ 'style-loader', 'css-loader' ]}
]
},
devServer: {
historyApiFallback: true,
},
plugins: [
new HtmlWebpackPlugin({
template: 'app/index.html'
})
]
};

react-router+antD/ How to highlight a menu item when press back/forward button?

I create a menu and want to highlight the item which i choose,and i did it. But when i press back/forward button,the menu item don't highlight. What should i do?
I have tried to use addEventListener but failed.
Have someone could give some advice?
class Sidebar extends React.Component {
constructor(props) {
super(props);
this.state={
test: "home"
}
this.menuClickHandle = this.menuClickHandle.bind(this);
}
componentWillMount(){
hashHistory.listen((event)=>{
test1 = event.pathname.split("/");
});
this.setState({
test:test1[1]
});
}
menuClickHandle(item) {
this.props.clickItem(item.key);
}
onCollapseChange() {
this.props.toggle();
}
render() {
var {collapse} = this.props;
return (
<aside className="ant-layout-sider">
<Menu mode="inline" theme="dark" defaultSelectedKeys={[this.state.test || "home"]} onClick={this.menuClickHandle.bind(this)}>
<Menu.Item key="home">
<Link to="/home">
<Icon type="user"/><span className="nav-text">用户管理</span>
</Link>
</Menu.Item>
<Menu.Item key="banner">
<Link to="/banner">
<Icon type="setting"/><span className="nav-text">Banner管理</span>
</Link>
</Menu.Item>
</Menu>
<div className="ant-aside-action" onClick={this.onCollapseChange.bind(this)}>
{collapse ? <Icon type="right"/> : <Icon type="left"/>}
</div>
</aside>
)
}
}
I could come up with a solution using WithRouter
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="home" />
<span>Home</span>
</NavLink>
</Menu.Item>
<Menu.Item key="/other">
<NavLink to="/other">
<Icon type="mobile"/>
<span>Applications</span>
</NavLink>
</Menu.Item>
<Menu.Item key="/notifications">
<NavLink to="/notifications">
<Icon type="notification" />
<span>Notifications</span>
</NavLink>
</Menu.Item>
</Menu>
</Sider>
)
}
}
export default withRouter(SideMenu);
Intercepts the current URL and then set selectedKeys(Note that it is not defaultSelectedKeys).
componentWillMount(){
hashHistory.listen((event)=>{
pathname = event.pathname.split("/");
if(pathname != null){
this.setState({
test:pathname[1]
});
}
});
}
you can set the paths of the link as keys on each Menu.Item . then selectedKeys={this.props.location.pathname}
<Menu
theme="light"
mode='inline'
selectedKeys={[this.props.location.pathname,]}
>
<Menu.Item key={item.path} style={{float:'right'}}>
Link to={item.path}>{item.name}</Link>
</Menu.Item>
{menulist}
</Menu>
Item would be set active according to the current path.
i added [] and trailing comma because selectedKeys accepts array while this.props.location.pathname is a String. i just code as hobby so idont know if its acceptable.
The following answer assumes you are using hooks. I know you are not in your question, but it might be useful for other people. In addition, this solution will work if you have nested paths such as /banner/this/is/nested, and it works not only when pressing back and forward buttons but also when refreshing the current page:
import React, { useState, useEffect } from 'react'
import { useHistory, useLocation } from 'react-router-dom'
import { Layout, Menu } from 'antd'
const { Sider } = Layout
const items = [
{ key: '1', label: 'Invoices', path: '/admin/invoices' },
{ key: '2', label: 'Service Details', path: '/admin/service-details' },
{ key: '3', label: 'Service Contract Details', path: '/admin/service-contract-details' },
{ key: '4', label: 'Cost Centers', path: '/admin/cost-centers' },
{ key: '5', label: 'Clients', path: '/admin/clients' },
{ key: '6', label: 'Vendors', path: '/admin/vendors' }
]
const Sidebar = () => {
const location = useLocation()
const history = useHistory()
const [selectedKey, setSelectedKey] = useState(items.find(_item => location.pathname.startsWith(_item.path)).key)
const onClickMenu = (item) => {
const clicked = items.find(_item => _item.key === item.key)
history.push(clicked.path)
}
useEffect(() => {
setSelectedKey(items.find(_item => location.pathname.startsWith(_item.path)).key)
}, [location])
return (
<Sider style={{ backgroundColor: 'white' }}>
<h3 style={{ paddingLeft: '1rem', paddingTop: '1rem', fontSize: '1.25rem', fontWeight: 'bold', minHeight: 64, margin: 0 }}>
Costek
</h3>
<Menu selectedKeys={[selectedKey]} mode='inline' onClick={onClickMenu}>
{items.map((item) => (
<Menu.Item key={item.key}>{item.label}</Menu.Item>
))}
</Menu>
</Sider>
)
}
export default Sidebar
This is how the sidebar will look like:
#Nadun's solution works for paths that don't contains arguments. If you're however using arguments in your routes, like me, here's a solution that should work for any route path, including /users/:id or crazy stuff like /users/:id/whatever/:otherId. It uses react-router's matchPath API, which uses the exact same logic as the Router component.
// file with routes
export const ROUTE_KEYS = {
ROOT: "/",
USER_DETAIL: "/users/:id",
};
export const ROUTES = {
ROOT: {
component: Home,
exact: true,
key: ROUTE_KEYS.ROOT,
path: ROUTE_KEYS.ROOT,
},
USER_DETAIL: {
component: Users,
key: ROUTE_KEYS.USER_DETAIL,
path: ROUTE_KEYS.USER_DETAIL,
},
};
.
// place within the App component
<Router>
<Layout>
<MyMenu />
<Layout>
<Layout.Content>
{Object.values(ROUTES).map((route) => (
<Route {...route} />
))}
</Layout.Content>
</Layout>
</Layout>
</Router>
.
// MyMenu component
const getMatchedKey = (location) =>
(
Object.values(ROUTES).find((route) =>
matchPath(location.pathname, route)
) || {}
).path;
const MyMenu = ({ location }) => {
return (
<Layout.Sider>
<AntMenu mode="inline" selectedKeys={[getMatchedKey(location)]}>
<AntMenu.SubMenu
title={
<React.Fragment>
<Icon type="appstore" />
Home
</React.Fragment>
}
>
<AntMenu.Item key={ROUTE_KEYS.ROOT}>
<Icon type="appstore" />
<span className="nav-text">
Some subitem
</span>
</AntMenu.Item>
</AntMenu.SubMenu>
<AntMenu.SubMenu
title={
<React.Fragment>
<Icon type="user" />
Users
</React.Fragment>
}
>
<AntMenu.Item key={ROUTE_KEYS.USER_DETAIL}>
<Icon type="user" />
<span className="nav-text">
User detail
</span>
</AntMenu.Item>
</AntMenu.SubMenu>
</AntMenu>
</Layout.Sider>
);
};
export default withRouter(MyMenu);
I do something like this but it doesn't seem to be reactive. Like if I navigate to a new page through a button (not from the menu items), it will not update the active link until the page refreshes.
import React from 'react';
import { StyleSheet, css } from 'aphrodite'
import { browserHistory, Link } from 'react-router';
import 'antd/lib/menu/style/css';
import 'antd/lib/icon/style/css';
import 'antd/lib/row/style/css';
import 'antd/lib/col/style/css';
import 'antd/lib/message/style/css';
import { appConfig } from '../../modules/config';
import { Menu, Icon, Row, Col, message } from 'antd';
const SubMenu = Menu.SubMenu;
const MenuItemGroup = Menu.ItemGroup;
const { appName } = appConfig;
const AppNavigation = React.createClass({
getInitialState() {
return {
current: this.props.pathname
};
},
handleClick(e) {
browserHistory.push(e.key);
this.setState({ current: e.key });
return;
},
render() {
return (
<Row className='landing-menu' type="flex" justify="space-around" align="middle" style={{height: 55, zIndex: 1000, paddingLeft: 95, color: '#fff', backgroundColor: '#da5347', borderBottom: '1px solid #e9e9e9'}}>
<Col span='19'>
<Link to='/'>
<h2 style={{fontSize: 21, color: '#fff'}}>
{appName}
<Icon type="rocket" color="#fff" style={{fontWeight: 200, fontSize: 26, marginLeft: 5 }}/>
</h2>
</Link>
</Col>
<Col span='5'>
<Menu onClick={this.handleClick} selectedKeys={[this.state.current]} mode="horizontal" style={{height: 54, backgroundColor: '#da5347', borderBottom: '0px solid transparent'}}>
<Menu.Item style={{height: 54, }} key="/">Home</Menu.Item>
<Menu.Item style={{height: 54, }} key="/signup">Signup</Menu.Item>
<Menu.Item style={{height: 54, }} key="/login">Login</Menu.Item>
</Menu>
</Col>
</Row>
);
},
});
export const App = React.createClass({
propTypes: {
children: React.PropTypes.element.isRequired,
},
componentWillMount(){
if (Meteor.userId()) {
browserHistory.push('/student/home')
}
},
render() {
return (
<div style={{position: 'relative'}}>
<AppNavigation pathname={this.props.location.pathname} />
<div style={{minHeight: '100vh'}}>
{ this.props.children }
</div>
</div>
);
}
});
EDIT:
the below works pretty well. pass down the pathname from react-router and pop that as a prop into selectedKeys
import React from 'react';
import { StyleSheet, css } from 'aphrodite'
import { browserHistory, Link } from 'react-router';
import 'antd/lib/menu/style/css';
import 'antd/lib/icon/style/css';
import 'antd/lib/row/style/css';
import 'antd/lib/col/style/css';
import 'antd/lib/message/style/css';
import { appConfig } from '../../modules/config';
import { Menu, Icon, Row, Col, message } from 'antd';
const SubMenu = Menu.SubMenu;
const MenuItemGroup = Menu.ItemGroup;
const { appName } = appConfig;
const AppNavigation = React.createClass({
getInitialState() {
return {
current: this.props.pathname
};
},
handleClick(e) {
browserHistory.push(e.key);
this.setState({ current: e.key });
return;
},
render() {
return (
<Row className='landing-menu' type="flex" justify="space-around" align="middle" style={{height: 55, zIndex: 1000, paddingLeft: 95, color: '#fff', backgroundColor: '#da5347', borderBottom: '1px solid #e9e9e9'}}>
<Col span='19'>
<Link to='/'>
<h2 style={{fontSize: 21, color: '#fff'}}>
{appName}
<Icon type="rocket" color="#fff" style={{fontWeight: 200, fontSize: 26, marginLeft: 5 }}/>
</h2>
</Link>
</Col>
<Col span='5'>
<Menu onClick={this.handleClick} selectedKeys={[this.props.pathname]} mode="horizontal" style={{height: 54, backgroundColor: '#da5347', borderBottom: '0px solid transparent'}}>
<Menu.Item style={{height: 54, }} key="/">Home</Menu.Item>
<Menu.Item style={{height: 54, }} key="/signup">Signup</Menu.Item>
<Menu.Item style={{height: 54, }} key="/login">Login</Menu.Item>
</Menu>
</Col>
</Row>
);
},
});
export const App = React.createClass({
propTypes: {
children: React.PropTypes.element.isRequired,
},
componentWillMount(){
if (Meteor.userId()) {
browserHistory.push('/student/home')
}
},
render() {
return (
<div style={{position: 'relative'}}>
<AppNavigation pathname={this.props.location.pathname} />
<div style={{minHeight: '100vh'}}>
{ this.props.children }
</div>
</div>
);
}
});
If you are using an array and mapping over it (as in my case) to set menu Items, They must be in the same order as they appear in the Side menu otherwise, an active bar or background will not be shown.
Environment: React Router V5, Ant Design V4.17.0
I solved this issues by override the onClick props of Menu.Item of antd
<Menu theme="light" mode="inline">
{menuItems.map((item) => {
return (
<NavLink
to={item.navigation}
component={({ navigate, ...rest }) => <Menu.Item {...rest} onClick={navigate} />}
key={item.key}
activeClassName="ant-menu-item-selected"
>
{item.icons}
<span>{item.name}</span>
</NavLink>
)
}
)}
</Menu>
The NavLink component will pass navigate prop to Menu.Item, we need to map it to onClick prop and click behaviour will work correctly.