摘要
本篇主要讲 ReactRouter 路由。
- 基础使用
- 嵌套路由
- 路由模式
- 路由跳转及传参
- 声明式导航
- 编程式导航
- 404
- 路由懒加载
什么是前端路由
一个路基path对应一个组件component,当打开浏览器输入一个path的时候,path对应的组件会在页面中进行渲染。
安装
在react项目中执行npm i react-router-dom
demo
以一个需求出发,我们创建一个可以切换登录页和列表页的路由系统。
-
/login:登录页
-
/list:列表页
分2步:
-
路由的配置,path 是路径,element是我们要渲染的UI,可以是组件 ,也可以是jsx,也就是一段div dom片段。都是可以的。
-
根组件里做路由绑定。
src/index.js
我们把路由配置先不抽离,直接写在index.js里,然后element我们先写个div简单演示,后边再优化。
import React from 'react'
import ReactDOM from 'react-dom/client'
import{createBrowserRouter,RouterProvider} from 'react-router-dom'
import './index.css'
// 1.路由配置
const router= createBrowserRouter([
{
path:'/',
element:<div>我是登录页</div>//<Login/>
},
{
path:'/list',
element:<div>我是列表页</div>//<List/>
},
])
ReactDOM.createRoot(document.getElementById('root')).render(
<React.StrictMode>
{/*2.路由绑定*/}
<RouterProvider router={router}/>
</React.StrictMode>
)
demo优化
改成日常项目中开发的常见形式。
路由配置从index.js里抽出。 element配置的UI改成组件。
路由导航的跳转
分两种:
-
声明式导航
-
编程式导航
声明式导航
是指通过在模板中通过组件描述出要跳转到哪里去。比如后台管理系统的左侧菜单通常使用这个种方式进行。
<Link to="/list">列表</Link>
Link:通过给组件to属性赋值上path页面路径来实现跳转,组件会被渲染成浏览器支持的a链接。
编程式导航
是指通过useNavigate
钩子得到导航的方法,然后通过调用方法以命令的形式进行路由跳转。比如在做完某个操作后执行跳转,可以选择这种方式,更加的灵活。
登录页,点击按钮跳转到列表页:
import {useNavigate} form 'react-router-dom'
const Login=()=>{
const navigate = useNavigate()
return(
<div>
我是登录页
<button onClick={()=>navigate('/list')}>跳转到列表页</button>
</div>
)
}
useNavigate:通过传入path路由地址参数实现跳转。
路由导航的跳转时传参
方式一:
问号传参,也叫searchParams传参。参数作为查询参数。
传入点:
navigate('/list?id=12&name=Macrolam')
接收参数:
使用的是 useSearchParams
钩子函数,调用后解构出params对象,然后通过其下边的get方法来获取指定key的参数值。
import {useSearchParams} from 'react-router-dom'
const List =()=>{
const [params] = useSearchParams()
const id = params.get('id')
const name = params.get('name')
return <div>我是列表页:{id} {name}</div>
}
export default List
方式二:
斜杠传参,也叫params传参。参数作为路径的一个部分,地址看起来更美观规整些。
传入点:
navigate('/list/12/Macrolam')
同时需要把路由注册地址位置上写上占位,否则找不到。
// ...
const router = createBrowserRouter([
{
path:'/list/:id/:name',
element:<List/>
}
])
//...
接收参数:
使用的是 useParams
钩子函数,调用后返回params对象,然后点语法读取到对应的参数key值。
import {useParams} from 'react-router-dom'
const List =()=>{
const params = useParams()
const id = params.id
const name = params.name
return <div>我是列表页:{id} {name}</div>
}
export default List
嵌套路由
在一个一级路由里又嵌套了其他路由,这种关系叫嵌套路由。内部的叫二级路由,当然还可以继续向下嵌套。
场景于:后台管理系统中。
Layout[一级] = Menu + MainUI[二级]
实现步骤
-
使用 children 属性配置 路由嵌套关系
-
使用 组件作为二级路由渲染的出口位置
案例
左侧是菜单项,右侧是对应的页面。
路由文件:
const router = createBrowserRouter([
{
path:'/',
element:<Layout/>,
children:[
{
path:'board',
element:<Board/>
},
{
path:'user',
element:<User/>
},
]
},
{
path:'/login',
element:<Login/>
},
])
一级路由分发页:layout.jsx
import {Link,Outlet} from 'react-router-dom'
const Layout =()=>{
return (
<div>
{/*Menu*/}
<Link to="/">着陆面板</Link>
<Link to="/user">用户管理</Link>
{/*MainUI 二级路由出口*/}
<Outlet/>
</div>
)
}
export default Layout
默认二级路由
就是当访问一个一级路由时,里面的二级路由也能默认选中一条进行渲染。
实现: 只需要在路由配置文件里,二级路由的位置去掉path,设置index属性为true。
比如:我们访问首页时候,默认给我们展示面板组件。
//...
import Layout form '../page/Layout'
import {createBrowserRouter} from 'react-router-dom'
const router = createBrowserRouter([
{
path:'/',
element:<Layout/>,
children:[
{
// path:'board',//del 删除不要
index:true,//add 新增一条此属性
element:<Board/>
},
{
path:'user',
element:<User/>
},
]
},
])
Vue也有类似的需求实现,vue里是把二级路由的path 置空。 这里是设置index=true。
404路由配置
当用户使用系统时,在地址栏输入的地址到我们的路由表里匹配不到时,可以使用404页面作为一个兜底渲染,提示用户当前路径下页面不存在。属于提升用户体验的。
404 的实现:
-
准备一个 NotFound 组件
-
在路由表数组的末尾,以 * 号 作为 路由path配置路由
const NotFound = ()=>{
return <div> 404 请访问的页面不存在,点击返回首页...</div>
}
//...
import NotFound form '../page/NotFound'
import {createBrowserRouter} from 'react-router-dom'
const router = createBrowserRouter([
{
path:'/',
element:<Layout/>,
children:[
{
path:'board',
element:<Board/>
},
{
path:'user',
element:<User/>
},
]
},
{
path:'/login',
element:<Login/>
},
//...
// 一定放到最底部
{
path:'*',
element:<NotFound/>
}
])
路由模式
和vue里一样有两种:
-
history: 由 createBrowserRouter 函数创建
-
hash: 由 createHashRouter 函数创建
切换路由模式,只需要切换一个API即可,其他都不用动。至于选择使用哪种模式,主要看下后台是否能配合。
路由模式 | url表现 | 底层原理 | 是否需要后台配合 |
---|---|---|---|
history | url/login | history对象 + pushState事件 | 需要 |
hash | url/#/login | 监听 hashChange 事件 | 不需要 |
hash 的路由模式:
import {createHashRouter} from 'react-router-dom'
const router = createHashRouter([
{
path:'/login',
element:<Login/>
},
//...
// 一定放到最底部
{
path:'*',
element:<NotFound/>
}
])
地址栏默认着陆页:http://localhost:8090/#/
会多了一段 /#/
登录页:http://localhost:8090/#/login
路由懒加载
首次访问时 ,只加载需要的js。不要全部页面js资源都加载上来。 而是用哪个路由,加载哪个路由下js资源。
目的:优化首次打开时间。
实现
-
把路由修改为由 React 提供的lazy 函数进行动态导入
-
使用 React 内置的 Suspense 组件 包裹路由中的 element 选项对应的组件
router.js
借助 lazy 函数改导入语句:
//...
import { lazy,Suspense } from 'react'
//1.lazy函数导入
const Home = lazy(() => import('@/pages/Home'))
const router = createBrowserRouter([
{
path: "/",
element:<Layout/>,
children:[
{
index:true,
element:<Suspense fallback={'加载中'}><Home/></Suspense>//2.Suspense 组件 包裹
}
]
}
])
其中 Suspense 标签身上的 fallback 属性 是配置,异步组件没加载上来之前显示的内容。