Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bugs in Sidebar Menu with React Router V4

I'm developing a single-page ReactJS Web app but I know I'm doing something wrong while defining my routing with React Router V4.

My problem is as follows: PrivateRoute in my routes.js file is not working as expected. That is, I don't know why but my sidebar menu, which is a child component of my main App, does not work properly: there are a few bugs when I click on the menu item of my PrivateRoute component (in this case, Page1). When I say bugs, I mean that when I click on the menu item of a PrivateRoute, the sidebar menu is misconfigured. The content of the component (Page1) is rendered but the menu item in the sidebar menu does not stay highlighted as it should be: it is redirected to the first menu item on the list, in this case MainHome.

Nonetheless, if I change the tag of my Page1 component from PrivateRoute to ConfigRoute in my routes.js file, everything works properly.

A sample from my files index.js (main), routes.js, App.js, and side-menu.js:

index.js (main) file:

import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import Routes from './routes';
import store from './store';

ReactDOM.render(
  <Provider store={store}>
    <Routes/>
  </Provider>,
  document.getElementById('root')
);

routes.js file:

import React, { Fragment } from 'react';
import { BrowserRouter, Switch, Route, Redirect } from 'react-router-dom';
import { connect } from 'react-redux';
import Login from './login';
import App from './App';
import MainHome from './home';
import Page1 from './page1';

const ConfigRoute = ({ component: Component, layout: Layout, ...rest }) => (
  <Route {...rest} render={(props) => (
    <Layout>
      <Component {...props}/>
    </Layout>
  )}/>
);

const PrivateRoute = ({ component: Component, layout: Layout, auth_status, ...rest }) => (
  <Route {...rest} render={(props) => (
    <Fragment>
      {auth_status === true
        ? (
          <Layout>
            <Component {...props}/>
          </Layout>
          )
        : (
          <Redirect to={{ pathname: "/", state: { from: props.location } }}/>
          )
      }
    </Fragment>
  )}/>
);

const Routes = (props) => (
  <Router>
    <Switch>
      <Route exact path="/" component={Login}/>
      <ConfigRoute path="/home" layout={App} component={MainHome}/>
      <PrivateRoute path="/page1" auth_status={props.auth_status} layout={App} component={Page1}/>
    </Switch>
  </Router>
);

const mapStatetoProps = state => ({
  auth_status: state.auth.isAuthenticated,
});

export default connect(mapStatetoProps)(Routes);

App.js file

import React, { Component } from 'react';
import { Layout } from 'antd';
import SideMenu from './side-menu';
import MainHeader from './main-header';
import MainFooter from './main-footer';

const { Content } = Layout;

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      collapsed: false,
    };
  }

  toggle = () => {
    this.setState({
      collapsed: !this.state.collapsed,
    });
  }

  render() {
    return (
      <Layout style={{ minHeight: '100vh' }}>
        <SideMenu collapsed={this.state.collapsed}/>
        <Layout>
          <MainHeader triggerParentUpdate={this.toggle} collapsed={this.state.collapsed}/>
          <Content style={{ margin: '24px 16px', padding: 24, background: '#ffffff', minHeight: 280 }}>
            {this.props.children}
          </Content>
          <MainFooter/>
        </Layout>
      </Layout>
    );
  }
}

export default App;

side-menu.js file:

import React from 'react';
import { Layout, Menu, Icon } from 'antd';
import { NavLink } from 'react-router-dom';

const { Sider } = Layout;
const SubMenu = Menu.SubMenu;

class SideMenu extends React.Component {

  render() {
    return (
      <Sider
        trigger={null}
        collapsible
        collapsed={this.props.collapsed}
        >
          <div className="logo"/>
          <Menu theme="dark" mode="inline" defaultSelectedKeys={['1']}>
            <Menu.Item key="1">
              <NavLink to="/home">
                <Icon type="home"/>
                <span>home</span>
              </NavLink>
            </Menu.Item>
            <Menu.Item key="2">
              <NavLink to="/page1">
                <Icon type="star-o"/>
                <span>page 1</span>
              </NavLink>
            </Menu.Item>       
          </Menu>
        </Sider>
    );
  }
}

export default SideMenu;
like image 876
Julia Avatar asked Jul 24 '18 12:07

Julia


People also ask

What is react router V4?

Since React works with only components, React Router v4 is component based. React Router gives us components like Route, Link, Switch, Prompt etc. to work with.

Why should I use React router for my website?

Because React Router allows us to render as many Routes as we'd like, and because we abstracted our routes to their own array, we can render different components at different sections of our page whenever the app's location matches the Route 's path. Want to learn more?

How to redirect user to login component in react router?

Redirect component’s to prop is used here to tell React Router where to redirect the user. to prop can also be an Object {pathname: ‘/login’, state: {…}} where state is any payload you want to pass to Login component as prop which is accessible from props.location.state inside Login component.

What is browserrouter and hashrouter in react-router-Dom?

React Router ( react-router-dom) provided BrowserRouter and HashRouter components which is starting point of your application. As we are using BrowserRouter ( path based ), we will import it like below in index.js.


1 Answers

I found one possible solution here - use the path as the menu keys and provide the location as the selectedKeys:

<Menu mode="inline" selectedKeys={[location.pathname]}>
  <Menu.Item key="/home">
    <Link to="/home">Home </Link>
  </Menu.Item>
...

You can test the solution here

Hope it helps!

like image 140
bamse Avatar answered Sep 22 '22 10:09

bamse