2022-01-19 react-router-dom V6 Antd Layout布局实现路由的切换

react-router-dom升级到V6之后API上还是有很多不同的
今天就使用vite+react-ts初始化项目,尝试一下
vite地址:https://cn.vitejs.dev/guide/#scaffolding-your-first-vite-project
react-router-dom地址:https://reactrouter.com/docs/en/v6/getting-started/installation
Antd地址:https://ant.design/components/layout-cn/

用到的路由API有: BrowserRouteruseRoutesRouteObjectLinkuseSearchParamsuseParamsmatchRoutesOutletuseLocationuseNavigate

开始
首先初始化项目

yarn create vite react-dom-6 --template react-ts

这样我们就使用vite脚手架初始化了一个react+ts的项目
进入到我们的项目里面

cd react-dom-6

接下来,把我们所需要的依赖安装一下

yarn
yarn add react-router-dom@6 antd --save

完事版本和目录就是这样的


image.png

启动我们项目

yarn dev     //  or: npm run dev

在浏览器打开网址
http://localhost:3000/

image.png

接下来把一些不必要的文件可以删除一下
image.png

App.css清空,然后把antd的css样式引入

@import "antd/dist/antd.css"

创建我们自己的页面
在src目录下,创建pages文件夹,用来存放我们自己的组件
在src目录下,创建routers文件夹,用来同意管理路由组件

  • 在routers文件夹创建路有组件index.tsx
import { lazy, ReactNode, Suspense } from 'react'
import { RouteObject } from 'react-router-dom'
// import AppLayout from '../AppLayout'
// import Detail from '../Detail'
// import Home from '../Home'
// import Login from '../Login'
// import User from '../User'

// 用懒加载实现优化
// const AppLayout = lazy(() => import('../AppLayout'));
const Detail = lazy(() => import('../Detail'));
const Home = lazy(() => import('../Home'));
const Login = lazy(() => import('../Login'));
const User = lazy(() => import('../User'));

// 切换页面会出现闪屏现象
// 解决思路:公共页面不采用懒加载的方式 并在App.tsx去除Suspense的包裹
import AppLayout from '../AppLayout';

// 实现懒加载的用Suspense包裹 定义函数
const lazyLoad = (children: ReactNode): ReactNode =>{
  return <Suspense fallback={<h1>Loading...</h1>}>
    {children}
  </Suspense>
}


export const routers: RouteObject[] = [

  {
    path: '/',
    element: <AppLayout />,
    //路由嵌套,子路由的元素需使用<Outlet />
    children: [
      {
        index: true,
        element: lazyLoad(<Home />)
      }, 
      {
        path: '/user/list',
        element: lazyLoad(<User />)
      },
      {
        path: '/user/detail/:id',
        element: lazyLoad(<Detail />)
      }
    ]
  },
  {
    path: '/login',
    element: lazyLoad(<Login />)
  }

]
  • main.tsx 组件
import ReactDOM from 'react-dom'
import {BrowserRouter as Router} from "react-router-dom"
import App from './App'

ReactDOM.render(
  <Router>
    <App />
  </Router>,
  document.getElementById('root'))
  • App.tsx 组件
    useRoutes:
    返回与当前位置匹配的路由元素,参数就是创建的路由对象
import { useRoutes } from 'react-router-dom';
import './App.css';
import { routers } from './pages/router'
function App() {
  return useRoutes(routers);
}
export default App;

依次看一下路由对应组件里面的内容

  • AppLayout.jsx 组件
    matchRoutes: 将给定路由匹配到某个位置并返回匹配数据。
    Outlet: 渲染子路由的元素(如果有)
    useLocation: 返回当前位置对象,该对象表示web中的当前URL
    Link: 用作链接跳转,会渲染成a标签
import { Layout, Menu, Breadcrumb } from 'antd';
import { UserOutlined, LaptopOutlined, NotificationOutlined } from '@ant-design/icons';
import { Link, matchRoutes, Outlet, useLocation } from 'react-router-dom';
import { useEffect, useState } from 'react';
import { routers } from './router';

const { SubMenu } = Menu;
const { Header, Content, Sider } = Layout;

export default function AppLayout() {
  const location = useLocation();
  const [defaultSelectedKeys, setDefaultSelectedKeys] = useState<string[]>([]);
  const [defaultOpenKeys, setDefaultOpenKeys] = useState<string[]>([]);
  const [isInit, setIsInit] = useState<Boolean>(false)

  useEffect(() => {
    const routes = matchRoutes(routers, location.pathname); // 返回匹配到的路由数组对象,每一个对象都是一个路由对象
    const pathArr: string[] = [];
    if(routes !== null) {
      routes.forEach((item) => {
      const path = item.route.path;
        if(path) {
          pathArr.push(path);
        }
      })
    }
    setDefaultSelectedKeys(pathArr);
    setDefaultOpenKeys(pathArr);
    setIsInit(true);
  }, [location.pathname]);
  if(!isInit) {
    return null;
  }
  return (
    <>
      <Layout>
        <Header className="header">
          <div className="logo" />
            
          <Menu theme="dark" mode="horizontal" defaultSelectedKeys={['2']}>
            <Menu.Item key="1">nav 1</Menu.Item>
            <Menu.Item key="2">nav 2</Menu.Item>
            <Menu.Item key="3">nav 3</Menu.Item>
          </Menu>
        </Header>
        <Layout>
          <Sider width={200} className="site-layout-background">
            <Menu
              mode="inline"
              {/* 根据url地址实现选中高亮 */}
              defaultSelectedKeys={defaultSelectedKeys}   
              defaultOpenKeys={defaultOpenKeys}
              style={{ height: '100%', borderRight: 0 }}
            >
              <SubMenu key="/user" icon={<UserOutlined />} title="用户管理">
                <Menu.Item key="/user/list">
                  <Link to='/user/list'>用户信息</Link>
                </Menu.Item>
                <Menu.Item key="2">option2</Menu.Item>
                <Menu.Item key="3">option3</Menu.Item>
                <Menu.Item key="4">option4</Menu.Item>
              </SubMenu>
              <SubMenu key="sub2" icon={<LaptopOutlined />} title="subnav 2">
                <Menu.Item key="5">option5</Menu.Item>
                <Menu.Item key="6">option6</Menu.Item>
                <Menu.Item key="7">option7</Menu.Item>
                <Menu.Item key="8">option8</Menu.Item>
              </SubMenu>
            </Menu>
          </Sider>
          <Layout style={{ padding: '0 24px 24px' }}>
            <Breadcrumb style={{ margin: '16px 0' }}>
              <Breadcrumb.Item>Home</Breadcrumb.Item>
              <Breadcrumb.Item>List</Breadcrumb.Item>
              <Breadcrumb.Item>App</Breadcrumb.Item>
            </Breadcrumb>
            <Content
              className="site-layout-background"
              style={{
                padding: 24,
                margin: 0,
                minHeight: 280,
              }}
            >
              <Outlet />
            </Content>
          </Layout>
        </Layout>
      </Layout>
    </>
  )
}
  • User.tsx 组件
    useSearchParams: 一个语法糖,用于通过URLSearchParams接口读取和写入搜索参数。
    URLSearchParams有get、getAll、has、set、sort、toString等方法
    用来获取URL传递的参数
import React from 'react'
import { Link, useSearchParams } from 'react-router-dom'

export default function User() {
  const [params, _] = useSearchParams();
  console.log(params.get("qq"));  // 获取参数
  return (
    <div>
     <ul>
       <li><Link to={'/user/detail/1'}>用户1</Link></li>
       <li><Link to={'/user/detail/2'}>用户2</Link></li>
       <li><Link to={'/user/detail/3'}>用户3</Link></li>
       <li><Link to={'/user/detail/4'}>用户4</Link></li>
     </ul>
    </div>
  )
}
  • Detail.tsx 组件
    useParams: 从当前参数返回动态参数的键/值对的对象与路由路径匹配的URL
import { useParams } from  'react-router-dom'

export default function Detail() {
  const params = useParams();

  return (
    <div>
      user Detail-- {params.id}
    </div>
  )
}

下面就是Login登陆组件了

  import { useNavigate } from 'react-router-dom';
  import { Button } from 'antd';
  export default funciton Login()  {
    const navigate = useNavigate();
    funciton clickToUser() {
      navigate('/');
    };

    return <Button type='primary' onClick={clickToUser} >登陆<Button/>
  }

差不多就是这个样子,完事之后是这个样子的

image.png

点击用户
image.png

就没了,有兴趣的同学可以尝试一下@~@

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,214评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,307评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,543评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,221评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,224评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,007评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,313评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,956评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,441评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,925评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,018评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,685评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,234评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,240评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,464评论 1 261
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,467评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,762评论 2 345

推荐阅读更多精彩内容