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有: BrowserRouter、useRoutes、RouteObject、Link、useSearchParams、useParams、matchRoutes、Outlet、useLocation、useNavigate
开始
首先初始化项目
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
完事版本和目录就是这样的
启动我们项目
yarn dev // or: npm run dev
在浏览器打开网址
http://localhost:3000/
接下来把一些不必要的文件可以删除一下
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/>
}
差不多就是这个样子,完事之后是这个样子的
点击用户
就没了,有兴趣的同学可以尝试一下@~@