下载
pnpm add react-router-dom
路由基本设置
1.配置路由表
react-router-domv6版本 可以跟vue一样配置路由表
创建文件夹router/index.tsx
import React from 'react'
import { createBrowserRouter } from 'react-router-dom'
import { Router } from '@remix-run/router' // 导入Router类型
import Home from '@/view/home'
import Login from '@/view/login'
// 创建路由
const router: Router = createBrowserRouter([
{
path: '/',
element: <Home /> //注册组件的第一种方式
},
{
path: '/login',
element: React.createElement(Login) // 注册组件的第二种方式
}
])
export default router
2.main.ts
初始
import ReactDOM from 'react-dom/client'
import App from './App'
ReactDOM.createRoot(document.getElementById('root')!).render(<App />)
修改后
import ReactDOM from 'react-dom/client'
import { RouterProvider } from 'react-router-dom'
import router from '@/router/index'
// 可以删除app.tsx 直接拿路由组件替换
ReactDOM.createRoot(document.getElementById('root')!).render(<RouterProvider router={router}></RouterProvider>)
完成
也可以不删除App.tsx
在App.tsx中
import { RouterProvider } from 'react-router-dom'
import router from './router'
export default function App() {
return <RouterProvider router={router}></RouterProvider>
}
效果是一样的
路由跳转的几种方式
1.使用NavLink组件
import React from 'react'
import { NavLink } from 'react-router-dom'
export default function login() {
return (
<div>
login组件<NavLink to='/'>跳转home</NavLink>
</div>
)
}
import React from 'react'
import { NavLink } from 'react-router-dom'
export default function home() {
return (
<div>
home组件:<NavLink to='/login'>跳转login</NavLink>
</div>
)
}
点击跳转home
成功跳转
2.使用link组件
和navlink一样 两者之间的区别是 navlink可以判断激活状态可以设置样式 link就是普通的a标签
import React from 'react'
import { Link } from 'react-router-dom'
export default function login() {
return (
<div>
login组件<Link to='/'>跳转home</Link>
</div>
)
}
3.使用Navigate组件 重定向
我们可以随便设置一个路由来展示作用
import React from 'react'
import { createBrowserRouter, Navigate } from 'react-router-dom'
import { Router } from '@remix-run/router' // 导入Router类型
import Home from '@/view/home'
import Login from '@/view/login'
// 创建路由
const router: Router = createBrowserRouter([
{
path: '/',
element: <Home />
},
{
path: '/login',
element: React.createElement(Login)
},
{
path: '/aaa',
element: <Navigate to='/login'></Navigate>
}
])
export default router
定义了一个/aaa的路由 访问之后让他重定向到login页面
访问aaa重定向到了login
4.使用编程路由导航 useNavigate
import React from 'react'
import { useNavigate } from 'react-router-dom'
export default function login() {
// 初始化路由
const $router = useNavigate()
// 点击跳转
const btn = () => {
$router('/')
}
return (
<div>
<p>login组件</p>
{/* 设置一个按钮 */}
<button onClick={btn}>点击跳转主页</button>
</div>
)
}
点击跳转成功
404页面
追加一条路由规则在路由表最下面 * 表示全部 上面路由表匹配不到 会最后走到404
{
path: '*',
element: <div>404!!! 当前页面不存在</div>
}
访问/666
嵌套路由
1.创建子路由
{
path: '/',
element: <Home />,
children: [
{
path: 'child',
element: <Child />
}
]
},
这个意思代表我们创建了一个子路由 子路由命名方式只写名称会自动拼接父路径
比如父级goods路由下面新增一个child 你可以写 child 或者是/goods/child 不能写/child
2.父组件设置二级路由出口
使用Outlet组件 Outlet相当于Vue中的routerview组件
import { Link, Outlet } from 'react-router-dom'
export default function home() {
return (
<div>
home组件:<Link to='/login'>跳转login</Link>
{/* 二级路由出口 */}
<Outlet />
</div>
)
}
动态路由传参
新增动态路由
以:参数名称进行动态传递
{
path: '/goods/:goodsId/order/:orderId',
element: <Goods />
},
组件通过useParams进行获取
import { useParams } from 'react-router-dom'
export default function goods() {
const params = useParams()
return (
<div>
<h3>商品Id:{params.goodsId}</h3>
<h3>订单Id:{params.orderId}</h3>
</div>
)
}
手动输入访问
loader
这个东西有点类似于vue-router中的路由独享守卫 在路由中配置loader函数 路由加载之前调用
{
path: '/goods/:goodsId/order/:orderId',
element: <Goods />,
// loader
loader: ctx => {
console.log(ctx)
return {}
}
},
浏览器打印 可以看到这个loader是在页面render之前触发的
在loader也可以拿到params参数 但是这样做意义不大
loader返回一个对象 在页面可以通过useLoaderData钩子拿到
{
path: '/goods/:goodsId/order/:orderId',
element: <Goods />,
// loader
loader: ctx => {
console.log(ctx)
return {
a: 1
}
}
},
const LoaderData = useLoaderData()
console.log(LoaderData)
举例1
在vue中我们可以使用独享守卫来进行接口的请求 拿到对应页面的数据 loader也可以发送异步请求
{
path: '/goods/:goodsId/order/:orderId',
element: <Goods />,
// loader
loader: async ctx => {
let res: { code: number; msg: string } = await new Promise((resolve, reject) => {
setTimeout(() => {
resolve({
code: 200,
msg: '请求成功'
})
}, 1000)
})
return {
...res
}
}
},
其实这样用的也比较少
举例2
当我们在做权限拦截的时候可以通过loader来进行判断
{
path: '/goods/:goodsId/order/:orderId',
element: <Goods />,
// loader
loader: async ctx => {
// 模拟一个token
let token = '10086'
// 判断没有登录去login
if (!token) return edirect('/login')
return {
username: 'admin',
token
}
}
},
我们再把token改为空字符串
{
path: '/goods/:goodsId/order/:orderId',
element: <Goods />,
// loader
loader: async ctx => {
// 模拟一个token
let token = ''
// 判断没有登录去login
if (!token) return edirect('/login')
return {
username: 'admin',
token
}
}
},
访问goods 返回login