案例背景

react-router-dom 更新到v6着实是一次大改,很多之前重要的组件和个性都改掉了,最显著的就是替换了Switch,Route里的Component属性等等。当然,对此次发现的问题的首恶是,更新删除了路由组件(class)默认自带的三个属性--match, history, location。不仅让编程式路由导航的罕用写法生效了,antd动静生成menu的view也受到了影响。同时react-router-dom在鼎力推广函数式组件的应用,所以能够通过一些hook来获取match,history和location,但类式组件就没那么侥幸啦,本文次要针对router的更新对类式组件的影响探讨。

原因是之前Menu中的selectedKeys属性须要通过this.props.location.pathname,从以后路由组件获取当初的path,router更新后当然就只能另求他法了。

这里先要阐明一下为什么不将Menu中的defaultSelectedKeys设置为'/home':如果用户是从'/'被重定向到'/home',此时会呈现问题,因为页面会渲染两次导致第二次无奈应用default。

老版本的动静生成menu的办法如下:

export default class LeftNav extends Component {    state = {        collapsed: false,    };    onCollapse = collapsed => {        this.setState({ collapsed });    };    createMenuNodes = (menuList) => {        return menuList.map(item => {            return item.children ?            (                <SubMenu key={item.key} icon={item.icon} title={item.title}>                    {this.createMenuNodes(item.children)}                </SubMenu>            ) :            (                <Menu.Item key={item.key} icon={item.icon}>                    <Link to={item.key}>{item.title}</Link>                </Menu.Item>            )        })    }       render() {        const { collapsed } = this.state        const path = this.props.location.pathname        return (            <Sider collapsible collapsed={collapsed} onCollapse={this.onCollapse}>                <div className="logo" style={collapsed === true ? { opacity: 0 } : { opacity: 1, transition: 'all 0.7s' }}>商品后盾管理系统</div>                <Menu theme="dark" selectedKeys={[path]} mode="inline">                    {                        this.createMenuNodes(menuList)                    }                </Menu>            </Sider>        )    }}

解决方案

最后想到的办法应用浏览器自带的window.location.pathname获取,然而点击导航时却并没有触发高亮变动,起因应该是react的diffing算法并不能监测到URL的变动,所以没有触发render。目前我只想到一个不太聪慧的办法,通过更新state获取path,但会多出很多条代码来解决门路异样时,state更新到home的问题,所以还要先判断以后path是不是无效的path。很轻便,集体愚见,如果有大佬能想到更好的优化办法请多指教。(最好的优化就是不必class组件~)

export default class LeftNav extends Component {    state = {        collapsed: false,        path: ''    };    onCollapse = collapsed => {        this.setState({ collapsed });    };    componentDidMount(){        const curPath = window.location.pathname        const effectivePaths = this.findEffectivePaths(menuList).flat() //扁平化数组        if (effectivePaths.indexOf(curPath) === -1) {            this.setState({path: '/home'}) //如果不是无效path,就指向home        } else {            this.setState({path: curPath})        }    }    //统计无效的path    findEffectivePaths = (menuList) => {        return menuList.map(item => {            if (item.children) {                return this.findEffectivePaths(item.children)            } else {                return item.key            }        })    }    //动静生成Menu,map+递归 (也能够通过reduce+递归)    createMenuNodes = (menuList) => {        return menuList.map(item => {            return item.children ?            (                <SubMenu key={item.key} icon={item.icon} title={item.title}>                    {this.createMenuNodes(item.children)}                </SubMenu>            ) :            (                <Menu.Item key={item.key} icon={item.icon}>                    <Link to={item.key} onClick={() => {this.setState({path: item.key})}}>{item.title}</Link>                </Menu.Item>            )        })    }       render() {        const { collapsed, path } = this.state        return (            <Sider collapsible collapsed={collapsed} onCollapse={this.onCollapse}>                <div className="logo" style={collapsed === true ? { opacity: 0 } : { opacity: 1, transition: 'all 0.7s' }}>商品后盾管理系统</div>                <Menu theme="dark" selectedKeys={[path]} mode="inline">                    {                        this.createMenuNodes(menuList)                    }                </Menu>            </Sider>        )    }}