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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值