react+ts項目實戰:如何使用withRouter?

1.我使用withRouter使解決什麼問題?

我在項目中使用了antd的Menu組件,其中defaultOpenKeys和defaultSelectedKeys兩個屬性要是設爲一個固定的值,每次刷新頁面的時候路由不變,但導航的高亮項就會重回最初的狀態,這跟實際需求不符,我需要高亮項跟路由是對應的。所以我需要把defaultOpenKeys和defaultSelectedKeys兩個屬性設置爲一個變化的值,此時若跟路由的變化對應上就再好不過了,但是由於在這組件中還獲取不到this.props.location,所以需要使用withRouter給它包裝一下。

const SystemSider = withRouter(class extends React.Component<RouteComponentProps> {
    render(){
        console.log(this.props, this.props.location.pathname.split('/')[1],this.props.location.pathname.split('/')[2])
        return (
            <Sider width={200} style={{ background: '#fff' }}>
                <Menu mode="inline" defaultOpenKeys={[this.props.location.pathname.split('/')[1]]} defaultSelectedKeys={[this.props.location.pathname.split('/')[2]]} style={{ height: '100%', borderRight: 0 }}>
                    <SubMenu key="official" title={ <span> <Icon type="user" /> 公文管理 </span> }>
                        <Menu.Item key='main'><Link to='/official/main'>收文登記</Link></Menu.Item>
                        <Menu.Item key='file'><Link to='/official/file'>檔案借閱</Link></Menu.Item>
                        <Menu.Item key='borrowManage'><Link to='/official/borrowManage'>借閱管理</Link></Menu.Item>
                        <Menu.Item key="4">規章制度</Menu.Item>
                        <Menu.Item key="5">質量管理</Menu.Item>
                        <Menu.Item key="6">合同模版</Menu.Item>
                    </SubMenu>
                    <SubMenu key="sub2" title={ <span> <Icon type="laptop" /> 審批流程</span>}>
                        <Menu.Item key="7">我的申請</Menu.Item>
                        <Menu.Item key="8">我的待辦</Menu.Item>
                    </SubMenu>
                </Menu>
            </Sider>
        )
    }  
});

 

2.怎麼使用withRouter?

withRouter是react-router-dom中的一個高階組件 ,要先引入才能使用

import { BrowserRouter as Router, Route, Link, Switch, withRouter, RouteComponentProps } from 'react-router-dom'

由於withRouter是一個高階組件,使用高階組件時有兩種方法:1⃣️函數式調用 2⃣️裝飾器

若使用裝飾器的話,在ts中,編譯器會對裝飾器作用的值做簽名一致性檢查,而我們在高階組件中一般都會返回新的組件,並且對被作用的組件的props進行修改(添加、刪除)等。這些會導致簽名一致性校驗失敗,ts會給出錯誤提示。若想使用裝飾器,要在@withRouter上面加上//@ts-ignore忽略ts校驗

3. 如何正確聲明高階組件呢?

裝飾器:將高階組件注入的屬性都聲明可選(通過Partial這個映射類型),或者將其聲明到額外的injected組件實例屬性上。

// @ts-ignore
@withRouter
class SystemSider extends React.Component<{}> {
    get injected() {
        return this.props as RouteComponentProps
    }

    render(){
        return (
            <Sider width={200} style={{ background: '#fff' }}>
                <Menu mode="inline" defaultOpenKeys={[this.injected.location.pathname.split('/')[1]]} defaultSelectedKeys={[this.injected.location.pathname.split('/')[2]]} style={{ height: '100%', borderRight: 0 }}>
                    <SubMenu key="official" title={ <span> <Icon type="user" /> 公文管理 </span> }>
                        <Menu.Item key='main'><Link to='/official/main'>收文登記</Link></Menu.Item>
                        <Menu.Item key='file'><Link to='/official/file'>檔案借閱</Link></Menu.Item>
                        <Menu.Item key='borrowManage'><Link to='/official/borrowManage'>借閱管理</Link></Menu.Item>
                        <Menu.Item key="4">規章制度</Menu.Item>
                        <Menu.Item key="5">質量管理</Menu.Item>
                        <Menu.Item key="6">合同模版</Menu.Item>
                    </SubMenu>
                    <SubMenu key="sub2" title={ <span> <Icon type="laptop" /> 審批流程</span>}>
                        <Menu.Item key="7">我的申請</Menu.Item>
                        <Menu.Item key="8">我的待辦</Menu.Item>
                    </SubMenu>
                </Menu>
            </Sider>
        )
    }  
};
export default SystemSider
// @ts-ignore
@withRouter
class SystemSider extends React.Component<Partial<RouteComponentProps>> {
    render(){
        console.log(this.props)
        return (
            <Sider width={200} style={{ background: '#fff' }}>
                {/** 這裏要使用非空類型斷言*/}
                <Menu mode="inline" defaultOpenKeys={[this.props.location!.pathname.split('/')[1]]} defaultSelectedKeys={[this.props.location!.pathname.split('/')[2]]} style={{ height: '100%', borderRight: 0 }}>
                    <SubMenu key="official" title={ <span> <Icon type="user" /> 公文管理 </span> }>
                        <Menu.Item key='main'><Link to='/official/main'>收文登記</Link></Menu.Item>
                        <Menu.Item key='file'><Link to='/official/file'>檔案借閱</Link></Menu.Item>
                        <Menu.Item key='borrowManage'><Link to='/official/borrowManage'>借閱管理</Link></Menu.Item>
                        <Menu.Item key="4">規章制度</Menu.Item>
                        <Menu.Item key="5">質量管理</Menu.Item>
                        <Menu.Item key="6">合同模版</Menu.Item>
                    </SubMenu>
                    <SubMenu key="sub2" title={ <span> <Icon type="laptop" /> 審批流程</span>}>
                        <Menu.Item key="7">我的申請</Menu.Item>
                        <Menu.Item key="8">我的待辦</Menu.Item>
                    </SubMenu>
                </Menu>
            </Sider>
        )
    }  
};
export default SystemSider

函數式調用:(除了開頭那種方法之外還可寫成如下所示:)

class SystemSider extends React.Component<{}> {
    get injected() {
        return this.props as RouteComponentProps
    }
    render(){
        console.log(this.props)
        return (
            <Sider width={200} style={{ background: '#fff' }}>
                <Menu mode="inline" defaultOpenKeys={[this.injected.location.pathname.split('/')[1]]} defaultSelectedKeys={[this.injected.location.pathname.split('/')[2]]} style={{ height: '100%', borderRight: 0 }}>
                    <SubMenu key="official" title={ <span> <Icon type="user" /> 公文管理 </span> }>
                        <Menu.Item key='main'><Link to='/official/main'>收文登記</Link></Menu.Item>
                        <Menu.Item key='file'><Link to='/official/file'>檔案借閱</Link></Menu.Item>
                        <Menu.Item key='borrowManage'><Link to='/official/borrowManage'>借閱管理</Link></Menu.Item>
                        <Menu.Item key="4">規章制度</Menu.Item>
                        <Menu.Item key="5">質量管理</Menu.Item>
                        <Menu.Item key="6">合同模版</Menu.Item>
                    </SubMenu>
                    <SubMenu key="sub2" title={ <span> <Icon type="laptop" /> 審批流程</span>}>
                        <Menu.Item key="7">我的申請</Menu.Item>
                        <Menu.Item key="8">我的待辦</Menu.Item>
                    </SubMenu>
                </Menu>
            </Sider>
        )
    }  
};
// @ts-ignore
export default withRouter(SystemSider)

參考文檔:https://blog.csdn.net/sinat_17775997/article/details/84203095

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