刷新页面后,活动菜单以粗体显示

时间:2019-06-24 11:14:56

标签: javascript reactjs redux antd

我有一个用React + Redux和Antdesign编写的应用程序。我的应用程序是一个仪表板应用程序。所以我在Ant设计https://ant.design/components/layout/

中使用了布局

当我单击侧面菜单时,活动菜单会变为粗体,这很好。但是当我刷新页面时,我需要它检查并检测路线和与粗体相关的菜单项。

我有一个状态为 Sidebar 的组件。在它里面,在componentDidMount中,我调用了一个函数,该函数将从mapDispatchToProps调度一个动作。减速器改变状态。但是在HTML代码中,在defaultSelectedKeys中,我无法设置活动菜单的数量。

Sidebar.js组件:

import React from 'react';
import { render } from 'react-dom';
import { connect } from 'react-redux'
import { Switch, BrowserRouter, Route, Link } from 'react-router-dom';

// antd
import { Layout, Breadcrumb, Menu, Icon } from 'antd';
const { Header, Content, Footer, Sider } = Layout;

// Helpers
import { Alert } from '../helpers/notifications';

// Components
import Home from '../components/Home';
// import Header from '../components/Header';
import NotFound from '../components/NotFound';
import PostsEditor from '../components/Posts/PostsEditor';

// Actions
import { setRouteActiveFlag } from '../actions/ui.action'

class Sidebar extends React.Component {

    componentDidMount () {
      const routes = {
        '/'       : 1,
        '/posts'  : 2,
        '/logout' : 3
      }

      this.props.detectActiveRoute(setRouteActiveFlag({
        routes:routes, 
        path:window.location.pathname
      }))
    }


    render() {

        const { selectedRoute } = this.props;
        console.log(selectedRoute);

        return (
            <div>
              <Layout>
                <Sider
                  style={{
                    overflow: 'auto',
                    height: '100vh',
                    position: 'fixed',
                    left: 0,
                  }} 
                  breakpoint="lg"
                  collapsedWidth="0"
                  onBreakpoint={broken => {
                    console.log(broken);
                  }}
                  onCollapse={(collapsed, type) => {
                    console.log(collapsed, type);
                  }}
                >
                  <div className="logo" >
                    Logo <br/><br/><br/>
                  </div>
                  <Menu theme="dark" mode="inline"  style={{ lineHeight: '64px' }} defaultSelectedKeys={[selectedRoute.toString() || '1']}>
                    <Menu.Item key="1">
                      <Link to="/" style={{ color:'#fff' }}>
                        <Icon type="user" />
                        <span className="nav-text">Home</span>
                      </Link>
                    </Menu.Item>
                    <Menu.Item key="2">
                      <Link to="/posts" style={{ color:'#fff' }}>
                        <Icon type="user" />
                        <span className="nav-text">Posts</span>
                      </Link>
                    </Menu.Item>
                    <Menu.Item key="3">
                      <a href="/logout" style={{ color:'#fff' }}>
                        <Icon type="user" />
                        <span className="nav-text">Logout</span>
                      </a>
                    </Menu.Item>
                  </Menu>
                </Sider>
                <Layout style={{ marginLeft: 200 }}>
                  <Content style={{ margin: '24px 16px 0', overflow: 'initial'}}>

                      <Breadcrumb style={{ margin: '0 0 20px 0' }}>
                        <Breadcrumb.Item>Home</Breadcrumb.Item>
                        <Breadcrumb.Item>List</Breadcrumb.Item>
                        <Breadcrumb.Item>App</Breadcrumb.Item>
                      </Breadcrumb>

                      <div style={{ padding: 24, background: '#fff', minHeight: 360 }}>
                        <Switch>
                            <Route path="/" exact component={Home} />
                            <Route path="/posts/:id?" component={PostsEditor} />
                            <Route component={NotFound}/>
                        </Switch>
                        <Alert stack={ { limit: 3 } } />
                      </div>

                  </Content>

                  <Footer style={{ textAlign: 'center' }}>Ant Design ©2018 Created by Ant UED</Footer>
                </Layout>
              </Layout>
            </div>
        );
    }
}

const mapStateToProps = (state, ownProps) => {
    return {
      state: state,
      props: ownProps,
      selectedRoute:state.ui.selectedRoute || 1
    }
}

const mapDispatchToProps = (dispatch, ownProps) => {
    return {
      detectActiveRoute: (obj) => dispatch(obj)
    }
}


export default connect(
    mapStateToProps,
    mapDispatchToProps
)(Sidebar)

ui.action.js

export const setRouteActiveFlag = (payload = 'global') => ({
  type: actions.SET_ROUTE_ACTIVE_FLAG,
  payload
});

ui.reducer.js

import { handleActions } from 'redux-actions';
import Immutable from 'seamless-immutable';
import * as actions from '../consts/action-types';


const initialState = Immutable({
  requests: {},
  selectedRoute:{}
});


export default handleActions({
  [actions.SET_ROUTE_ACTIVE_FLAG]: (state, action) => {
    if (action.payload.routes && action.payload.path && action.payload.routes[ action.payload.path ]) {
        return state.set('selectedRoute', action.payload.routes[ action.payload.path ])
    }else{
        return state.set('selectedRoute', 1)
    }
  }
}, initialState);



请帮助我找到最佳和简单的做法。

3 个答案:

答案 0 :(得分:2)

无需使用redux,只需使用react-router获取当前路径名并将其传递给defaultSelectedKeys

<Menu defaultSelectedKeys={[this.props.location.pathname]}>
  ...
  .....
</Menu>

如果您不知道如何获取路径名,请查看此answer

答案 1 :(得分:1)

以下答案假定您正在使用钩子。我知道从您的问题来看,您没有使用钩子,但对其他人可能有用。此答案不仅适用于刷新,而且适用于按向后和向前按钮:

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

您的侧边栏将如下所示:

enter image description here

答案 2 :(得分:0)

您可以通过调节并以这种方式添加类来在菜单中添加任何CSS。

<MenuItem className={ (this.props.location.pathname==='/yourRoute')? 'active' : '' } >

</MenuItem>

如果您遇到任何类型的未定义错误,则可以使用“ withRouter” HOC

以这种方式。

在要获取该位置道具的组件中,您将首先导入

import {withRouter} from 'react-router-dom';

然后您可以通过这种方式将其导出。

export default withRouter(YourComponent);

最终代码看上去与此类似

import React, {Fragment, Component} from 'react';
import {withRouter, Link } from 'react-router-dom';

class Menu extends Component {

   render(){

     const {pathname} = this.props.location;

     return (
        <Fragment>
            <div id="sidebar-menu" className="sidebar-menu">

                    <ul>
                        <li className={(pathname==='/dashboard' || pathname==='/')?'active':''}> 
                            <Link to="/dashboard">Dashboard</Link>
                        </li>

                        <li className={(pathname==='/properties')?'active':''}> 
                            <Link to="/properties">Properties</Link>
                        </li>
                    </ul>

            </div>
        </Fragment>
     );

     }

}
export default withRouter(Menu);