React-Router-domV6 + AntdV5 导航菜单实现路由跳转

因为是主学后端,为了做项目学点前端。下面的代码都是个人练习,主要是实现导航菜单进行路由跳转,分享一下学习收获和解决一些bug的所得。不足之处还请大佬多指点。

附注:本文章多是参考其他文章的代码案例进行实现,主要自己的东西还是解决bug的心得

参考文章:

http://t.csdn.cn/KzyNr 

目录

代码如下

排错


提示:需要学习导航菜单实现路由跳转的功能的请参考上面文章,本文有价值的不过只是排错和收获。欢迎指正!

代码如下

1. 依赖

    "antd": "5",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-router-dom": "^6.4.5",
    "react-scripts": "5.0.1",
    "web-vitals": "^2.1.4"

2. 包结构

红色方块是主要的组件。

用的是编程式跳转的方式 

3. 代码实现

配置主页和组件 

App.js

import {
    Route,
    Navigate,
    Routes
} from 'react-router-dom'

import Main from './Main';
import CardTest from './pages/CardTest';
import LayOutPage from './pages/LayOutPage';
import TestPage1 from './pages/testPage1';

export default function App() {
    return (
        //这里用Routes,后面再来解释原因。
        <Routes>
            <Route path='*' element={<Navigate to="/home" />} />
            <Route exact path='/home' element={<Main />}>
                <Route exact path='/home/first' element={<CardTest />} />
                <Route exact path='/home/second' element={<LayOutPage />} />
                <Route exact path='/home/third' element={<TestPage1 />} />
            </Route>
        </Routes>

    )
}

主页组件

Main.js

import React, { Component } from 'react';
import { Breadcrumb, Layout } from 'antd';
import { Outlet } from 'react-router-dom'
import './index.css'; //这里是简单将部分样式转移到css,是个人尝试以及练习css,不必在意

import NavigateComponent from './components/headMenu';

const { Header, Content, Footer } = Layout;


class Main extends Component {

  render() {
    return (

      <Layout>
        <Header
          style={
   
   {
            position: 'sticky',
            top: 0,
            zIndex: 1,
            width: '100%',
          }}
        >
          <div
            style={
   
   {
              float: 'left',
              width: 120,
              height: 31,
              margin: '16px 24px 16px 0',
              background: 'rgba(255, 255, 255, 0.2)',
            }}
          />
          {/* 渲染导航菜单组件 */}
          <NavigateComponent />
        </Header>


        <Content
          className="site-layout"
          style={
   
   {
            padding: '0 50px',
          }}
        >
          <Breadcrumb
            style={
   
   {
              margin: '16px 0',
            }}
          >
            <Breadcrumb.Item>Home</Breadcrumb.Item>
            <Breadcrumb.Item>List</Breadcrumb.Item>
            <Breadcrumb.Item>App</Breadcrumb.Item>

          </Breadcrumb>

          <div id='context'
          >
            内容组件
            {/* 路由跳转 */}
            <Outlet />
          </div>
        </Content>
        <Footer
          style={
   
   {
            textAlign: 'center',
          }}
        >
          To be a better man
        </Footer>

      </Layout>

    )
  }

};

export default Main;

路由跳转的组件,其他的都是简单的展示,主要目的只是展示效果。下面只展示一个组件,其他的组件名由上面App.js可见,我放在page包下

LayOutPage.js

import {Component} from "react";

export default class LayOutPage extends Component {
    render(){
        return (
            <div>看看我!</div>
        )
    }
}

导航菜单组件

/components/headMenu.js

import { Component } from "react";
import { Menu } from "antd";

import widthUseNavigate from "../utils/getUseNavigate";


class HeaderMenu extends Component {

    constructor(props) {
        super(props);
        this.state = {
            items: [
                {
                    key: '/home/first',
                    label: `组件1`
                },
                {
                    key: '/home/second',
                    label: `组件2`
                },
                {
                    key: '/home/third',
                    label: `组件3`
                }
            ]
        }
    }

    click = (e) => {
        this.props.to(e.key);
    }

    render() {
        return (
            /* 导航菜单组件 */
            <Menu
                theme="dark"
                mode="horizontal"
                defaultSelectedKeys={['/first']}
                items={this.state.items}
                onClick={this.click}
            />
        )
    }
}

// 使用高阶组件包裹当前类组件
const NavigateComponent = widthUseNavigate(HeaderMenu);
export default NavigateComponent;

注意click函数,this.prop.to的实现需要下面高阶组件的配合实现。

高阶组件,包裹useNavigate()功能

widthUseNavigate.js

注:这一段代码真正是cv大佬文章的,我自己水平是写不出的哈哈。

文章:http://t.csdn.cn/KzyNr

import { useNavigate } from 'react-router-dom'
// 高阶组件包装useNavigate()功能
// 原因:类组件中无法使用useNavigate(),会报错
// error: React Hook "useNavigate" cannot be called in a class component.
function widthUseNavigate(WrapCompontent) {
  // 设置别名
  WrapCompontent.displayName = `widthUseNavigate${getDisplayName(WrapCompontent)}`
  return function NavigateCompont() {
    const navigate = useNavigate()
    // 给传入的组件新增一个to方法,传给原始组件的props,在原始组件中通过this.props.to(参数)使用
    return <WrapCompontent to={navigate}></WrapCompontent>
  }
}
 
// 别名
function getDisplayName(WrapCompontent) {
  return WrapCompontent.displayname || WrapCompontent.name || 'Component'
}
 
export default widthUseNavigate

最后是渲染到页面

index.js

import ReactDOM from 'react-dom/client';
// import './index.css';
import App from './App';
import {BrowserRouter as Router} from 'react-router-dom';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
    <Router>
        <App/>
    </Router>
);

这里<App/>包裹了<Router>,也是我在排错时参考大佬文章做出的调整。下面再提。

到这里,代码实现完成。项目启动后功能正常实现

排错

中间许多排错过程真可谓是悠悠万难哈哈。没做记录,下面来说一下做出了那些排错调整,以及原因。

第一点:

在一整个模仿加cv简单的实现导航菜单和主页面功能。开始尝试实现路由跳转的时候,被<Router>标签包裹的页面无法显示,翻遍百度之后尝试了一种做法就是将要作为渲染到页面的App组件用<Router>标签包裹,而App组件中管理的子路由组件用<Routes>包裹。

index.js

import ReactDOM from 'react-dom/client';
// import './index.css';
import App from './App';
import {BrowserRouter as Router} from 'react-router-dom';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
    <Router>
        <App/>
    </Router>
);

App.js

import {
    Route,
    Navigate,
    Routes
} from 'react-router-dom'

import Main from './Main';
import CardTest from './pages/CardTest';
import LayOutPage from './pages/LayOutPage';
import TestPage1 from './pages/testPage1';

export default function App() {
    return (
        <Routes>
            <Route path='*' element={<Navigate to="/home" />} />
            <Route exact path='/home' element={<Main />}>
                <Route exact path='/home/first' element={<CardTest />} />
                <Route exact path='/home/second' element={<LayOutPage />} />
                <Route exact path='/home/third' element={<TestPage1 />} />
            </Route>
        </Routes>

    )
}

原因是:

 而<Router>标签不能够双层包裹,而App组件中管理路由需要用<Router>标签包裹。所以换用<Routes>标签解决

 第二点:

在导航菜单中实现路由跳转控制,而useNavigate功能无法在类组件中实现,会报错

error: React Hook "useNavigate" cannot be called in a class component.

所以用高阶组件包裹useNavigate方法,再暴露给导航菜单组件调用

getUseNavigate.js

import { useNavigate } from 'react-router-dom'
// 高阶组件包装useNavigate()功能
// 原因:类组件中无法使用useNavigate(),会报错
// error: React Hook "useNavigate" cannot be called in a class component.
function widthUseNavigate(WrapCompontent) {
  // 设置别名
  WrapCompontent.displayName = `widthUseNavigate${getDisplayName(WrapCompontent)}`
  return function NavigateCompont() {
    const navigate = useNavigate()
    // 给传入的组件新增一个to方法,传给原始组件的props,在原始组件中通过this.props.to(参数)使用
    return <WrapCompontent to={navigate}></WrapCompontent>
  }
}
 
// 别名
function getDisplayName(WrapCompontent) {
  return WrapCompontent.displayname || WrapCompontent.name || 'Component'
}
 
export default widthUseNavigate

在导航菜单调用,并将返回的增强后的组件暴露

 以上是文章的全部,再次感谢各位大佬的分享和帮助。


参考文章:http://t.csdn.cn/KzyNr 

                  Cannot read properties of undefined (reading 'pathname') | bobbyhadz

猜你喜欢

转载自blog.csdn.net/Ccc67ol/article/details/128298437
今日推荐