【问题标题】:Bold active menu after refreshing the page刷新页面后的粗体活动菜单
【发布时间】:2019-11-06 04:34:31
【问题描述】:

我有一个使用 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);



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

【问题讨论】:

标签: javascript reactjs redux antd


【解决方案1】:

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

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

看看这个answer ,如果你不知道如何获取路径名

【讨论】:

  • 这不再是解决方案,因为 props.location 未定义。一些人建议使用钩子(useEffect(() => { return history.listen((location) => { .. )。但是这个代码在用户点击 BrowserRouter 链接之前不起作用。
【解决方案2】:

您可以通过调节和添加类来在菜单中添加任何 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);

【讨论】:

    【解决方案3】:

    以下答案假设您正在使用钩子。我知道从您的问题中您没有使用钩子,但它可能对其他人有用。这个答案不仅在刷新时有效,而且在按下后退和前进按钮时有效:

    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
    
    

    您的侧边栏将如下所示:

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-11-22
      • 1970-01-01
      • 2017-01-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多