react實戰--antd、react-router-dom v4 解決菜單和地址同步問題

antd、react-router-dom v4 解決菜單和地址同步問題

最近使用react開發項目,使用react-router-dom v4,並結合antd\redux。
遇到問題:模塊熱加載或者瀏覽器強制刷新後,頁面更新後菜單欄的激活列和地址和展示內容往往不同步。
使用antd的Menu組件和react-router-dom結合,解決該問題,故分享下希望對小夥們有所幫助。

到發文時使用的版本是:
- react (v15.5.4)
- react-router-dom (v4.2.2)
- antd (v2.9.3)
- redux (v3.6.0)


項目功能(部分):

頁面 路徑
頁面登錄 /
主頁面(包含側邊欄菜單–antd Menu) /home
用戶列表 /home/users
角色列表 /home/roles

頁面入口,routers.jsx

import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter, Route, Redirect, Switch } from 'react-router-dom'
import { createStore } from 'redux';
import { Provider } from 'react-redux';
import Reducer from './reducers';
import LoginContainer from './container/loginContainer';
import Home from './components/home/home';
import './fontIcon/index.css';
const Store = createStore(Reducer)
const Root = () => (
    <BrowserRouter>
        <Provider store={Store}>
            <div>
                <Switch>
                    <Route exact path="/" component={LoginContainer}/>
                    <Route path="/home" component={Home}/>
                    <Redirect to="/"/>
                </Switch>
            </div>
        </Provider>
    </BrowserRouter>
);

const dom = document.getElementById('root');

ReactDOM.render(<Root />, dom);

BrowserRouter:基於瀏覽器H5 history API的一種Router,推薦使用這種方式。

Route : 是路由中最最基礎和最最重要的,其path爲要匹配地址欄的路徑(可以是絕對匹配,也可以是匹配一部分獲取一部分,項目結構簡單,暫用絕對匹配),component爲匹配成功後要加載的模塊(同方式還有其他兩種,component爲最常用,另外兩種暫不介紹了)
Route exact 使用該模式後,地址是絕對匹配,比如/home 如果不設置exact,當地址爲/home/group時也會匹配,但使用之後,則不會。

Redirect :重定向路由,主要用於匹配無效地址到指定路徑。例如上例中,如果輸入”http://XXXXX:000/baidu” 會被重定向到http://XXXXX:000/,加載登錄模塊。

Switch : 這個是v4新增加的,是爲了保證路由匹配的唯一性,從上往下,一旦匹配上,就不再往後匹配了。例如上面代碼中包裹的Route,如果不加switch,當地址欄輸入http://XXXXX:000/時,第一條route會匹配,加載登錄模塊,第三條路由也會匹配,重定向到/,會導致打開的路徑重複打開,此時控制檯會提示重複執行路徑。


頁面入口,routers.jsx

import React from 'react'
import { Layout, Menu, Icon } from 'antd'
import {  Route, Switch, Redirect, NavLink } from 'react-router-dom'
import UserListContainer from '../../container/userListContainer';
import RoleListContainer from '../../container/roleListContainer';

import Logout from '../logout'
const { Content, Sider} = Layout;
import './home.less';

const Home = (props) => {
    return (
        <Layout className="sider_layout" style={{ minHeight: '100vh'}}>
            <Sider collapsed={false} >
                <div className="logo header_title">
                    項目管理
                </div>
                <Menu theme="dark" selectedKeys={[location.pathname]} mode="inline" >
                    <Menu.Item key="/home/users">
                        <NavLink to="/home/users"><Icon type="team" />用戶列表</NavLink>
                    </Menu.Item >
                    <Menu.Item key="/home/roles">
                        <NavLink to="/home/roles"><Icon type="solution" />角色列表</NavLink>
                    </Menu.Item >
                    <Menu.Item>
                        <Logout history={props.history}/>
                    </Menu.Item >
                </Menu>
            </Sider>
            <Layout>
                <Content className="us_content">
                    <Switch>
                        <Route path="/home/users" component={UserListContainer} />
                        <Route path="/home/roles" component={RoleListContainer} />
                    </Switch>

                </Content>
            </Layout>
        </Layout>
    )
}

export default Home

Menu:antd提供的便捷組件,類似bootstrap。其中子菜單是用戶列表和角色列表,其selectedKeys屬性爲選中哪個子菜單,該值對應Menu.Item的key。
在該項目中,我將key和路徑設置爲一樣的值,方便直接從location路徑中直接取值後修改選中狀態。

NavLink:和Link一樣,文檔說NavLink可以自定義激活狀態和類名,這裏使用NavLink和Link都可,暫沒有區別。


selectedKeys是和地址欄對應的,也就是解決本文問題的關鍵,當該值和地址欄同步後,無論頁面強制刷新還是熱加載,菜單欄選中的菜單和顯示的內容和地址都是同步的。

location:該值要想獲取到,需要使用react-router-dom的withRouter。使用withRouter處理XXXContainer之後,可以在XXXContainer連接的組件中調用location對象,獲取需要的值。

使用示例:

const RoleListContainer = connect(
    mapStateToProps,
    mapDispatchToProps
)(rolesList);
//withRouter 不需要引入
export default withRouter(RoleListContainer)

總結
react-router-dom v4 不再像之前的v3一樣,需要將所有的路由寫在一起,而是將各個模塊作爲dom一樣直接嵌套使用,Route匹配後加載的組件還可以包含多個Route,這樣的使用使加載組件更爲便捷,結構更加清晰。

不足之處還望小夥伴們多多提出,多多指教~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章