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