ReactRouter
# 前端路由
一个路径 path 对应一个组件 component 当我们在浏览器中访问一个 path 的时候,path 对应的组件会在页面中进行渲染
const routes = [
{
path: '/about',
component: About,
},
{
path: '/article',
component: Article,
},
]
# 安装
# 安装最新的ReactRouter包
npm i react-router-dom
# 快速开始
浅使
index.js
import React from 'react'
import ReactDOM from 'react-dom/client'
const router = createBrowserRouter([
{
path:'/login',
element: <div>登录</div>
},
{
path:'/article',
element: <div>文章</div>
}
])
ReactDOM.createRoot(document.getElementById('root')).render(
<RouterProvider router={router}/>
)
/src/page
目录下创建页面文件夹,如Login
、Article
- 页面文件夹中创建
index.js
const Article = () => {
return <div>我是文章页</div>
}
export default Article
- 创建
/src/route
目录,并创建文件index.js
import Login from '../page/Login';
import Article from '../page/Article';
import { createBrowserRouter } from 'react-router-dom';
const router = createBrowserRouter([
{
path: '/login',
element: <Login />
},
{
path: '/article',
element: <Article />
}
])
export default router;
- 应用入口文件(
/src/index.js
)渲染 RouterProvider
...
// 1. 导入路由router
import router from './router'
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
{/* 2. 路由绑定 */}
<RouterProvider router={router}/>
</React.StrictMode>
);
# 路由导航
# 声明式 - Link
Link v6.26.1 | React Router (opens new window)
声明式导航是指通过在模版中通过 <Link/>
组件描述出要跳转到哪里去,比如后台管理系统的左侧菜单通常使用这种方式进行
<Link to="/article">文章</Link>
# 编程式导航 - useNavigate
useNavigate v6.26.1 | React Router (opens new window)
编程式导航是指通过 useNavigate
钩子得到导航方法,然后通过调用方法以命令式的形式进行路由跳转,比如想在登录请求完毕之后跳转就可以选择这种方式,更加灵活
import { useNavigate } from "react-router-dom";
const Login = () => {
const navigate = useNavigate()
return (
<div>
我是登录页
<button onClick={() => navigate('/article')}>跳转到文章页</button>
</div>
)
}
export default Login;
# 导航传参
以下演示
useNavigate
方式,Link
同理
# searchParams
useSearchParams v6.26.1 | React Router (opens new window)
传递
navigate('/article?id=1001&name=jack')
接收
import * as React from "react";
import { useSearchParams } from "react-router-dom";
function App() {
let [searchParams] = useSearchParams()
let id = params.get('id')
return (
<div>
...
</div>
);
}
# params
useParams v6.26.1 | React Router (opens new window)
路由配置
/src/router/index.js
:添加占位符 :id
...
const router = createBrowserRouter([
...
{
path:'/article/:id',
element: <div>文章</div>
}
])
...
传递
navigate('/article/1001')
接收
const Article = () => {
const params = useParams()
const id = params.id
return <div>我是文章页{id}</div>
}
export default Article
# 嵌套路由(二级路由)
在一级路由中又内嵌了其他路由,这种关系就叫做嵌套路由,嵌套至一级路由内的路由又称作二级路由,例如:
# 创建页面
/src/Layout/index.js
:一级路由
const Layout = () => {
return (
<div>我是一级路由</div>
<Outlet />
)
}
export default Layout
/src/About/index.js
:二级路由/src/Board/index.js
:二级路由
# 配置
/src/router/index.js
import Layout from '../page/Layout';
import Board from '../page/Board';
import About from '../page/About';
import { createBrowserRouter } from 'react-router-dom';
const router = createBrowserRouter([
{
path: '/',
element: <Layout />,
children: [
{
path: 'board',
element: <Board />
},
{
path: 'about',
element: <About />
}
]
},
])
export default router;
路由懒加载
上述写法会在首次打开网页时加载所有页面的资源,会导致加载速度慢,使用 lazy
函数和 Suspense
组件可实现懒加载
import Layout from '../page/Layout';
- import Board from '../page/Board';
- import About from '../page/About';
+ const Publish = lazy(() => import('@/pages/Board'))
+ const About = lazy(() => import('@/pages/About'))
import { createBrowserRouter } from 'react-router-dom';
const router = createBrowserRouter([
{
path: '/',
element: <Layout />,
children: [
{
path: 'board',
- element: <Board />
+ element: (
+ <Suspense fallback={'加载中'}>
+ <Board />
+ </Suspense>
+ )
},
....
# 完善一级路由页面
const Layout = () => {
return (
<div>我是一级路由
<Link to="/board">面板</Link>
<Link to="/about">关于</Link>
{ /* 配置二级路由的出口 */}
<Outlet />
</div>
)
}
export default Layout
PS:跳转到的页面为 /board
,而不是 /layout/board
# 配置默认二级路由
只需要在二级路由的位置去掉 path
,设置 index
属性为 true
children: [
{
- path: 'board',
+ index: true
element: <Board />
},
{
path: 'about',
element: <About />
}
]
原来跳转到 /board
要改成跳转 /
- <Link to="/board">面板</Link>
+ <Link to="/">面板</Link>
# 404 路由
- 准备一个 NotFound 组件
- 在路由表数组的末尾,以
*
作为路由path
配置路由
{
path: '*',
element: <NotFound />
}
# 路由模式
各个主流框架的路由常用的路由模式有俩种,history 模式和 hash 模式,ReactRouter 分别由 createBrowerRouter
和 createHashRouter
函数负责创建
路由模式 | url 表现 | 底层原理 | 是否需要后端支持 |
---|---|---|---|
history | url/login | history 对象 + pushState 事件 | 需要 |
hash | url/#/login | 监听 hashChange 事件 | 不需要 |
route/index.js
...
const router = createBrowserRouter([
...
])
export default router;
# 路由鉴权
业务背景:封装
AuthRoute
路由鉴权高阶组件,实现未登录拦截,并跳转到登录页面 实现思路:判断本地是否有 token,如果有,就返回子组件,否则就重定向到登录 Login
实现步骤
- 在 components 目录中,创建
AuthRoute/index.jsx
文件 - 登录时,直接渲染相应页面组件
- 未登录时,重定向到登录页面
- 将需要鉴权的页面路由配置,替换为 AuthRoute 组件渲染
代码实现 components/AuthRoute/index.jsx
import { getToken } from '@/utils'
import { Navigate } from 'react-router-dom'
const AuthRoute = ({ children }) => {
const isToken = getToken()
if (isToken) {
return <>{children}</>
} else {
return <Navigate to="/login" replace />
}
}
export default AuthRoute
src/router/index.jsx
import { createBrowserRouter } from 'react-router-dom'
import Login from '@/pages/Login'
import Layout from '@/pages/Layout'
import AuthRoute from '@/components/Auth'
const router = createBrowserRouter([
{
path: '/',
element: <AuthRoute><Layout /></AuthRoute>,
},
{
path: '/login',
element: <Login />,
},
])
export default router