react路由
前言:
react 18.x + router@6
# 1.项目创建
create-react-app project
cd project
yarn start
# 2.整理项目架构
project
├── public
│ ├── favicon.ico
│ ├── index.html
│ ├── logo192.png
│ ├── logo512.png
│ ├── manifest.json
│ └── robots.txt
├── src
│ ├── views
│ │ ├── App.css
│ │ └── App.js
│ ├── index.css
│ ├── index.js
│ └── logo.svg
├── README.md
├── package-lock.json
└── package.json
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 3.使用sass 预处理
yarn add sass
# 4.使用router
目前最新版 路由是 react-router-dom@6.x
yarn add react-router-dom
import { HashRouter,Link,Route,Routes } from 'react-router-dom'
# 4.1 路由核心组件
- HashRouter
作用:包裹整个应用,一个React应用只需要使用一次
两种常用Router:BrowerRouter和HashRouter(history和hash路由)
- Link
作用:用于指定导航链接,完成路由跳转
语法说明:组件通过to属性指定路由地址,最终会渲染为a链接元素
- Routes
作用:提供一个路由出口,满足条件的路由组件会渲染到组件内部 相当于老版本:Switch
- Route
作用:用于指定导航链接,完成路由匹配
语法说明:path属性指定匹配的路径地址,element属性指定要渲染的组件
# 4.2 路由案例
一级路由: 首页 Home.jsx ,订单页 Order.jsx , 个人中心 Mine.jsx
首页下二级路由: 推荐 Recommend.jsx 【默认打开】 商品列表 Goods.jsx
配置实现
1.创建页面级jsx 组件
2.导入到根组件中
3.配置 HashRouter
# 1.创建页面级 组件
src
├── assets
│ └── logo.svg
├── views
│ ├── 404
│ │ └── NotFound.jsx
│ ├── home
│ │ ├── Goods.jsx
│ │ ├── Home.jsx
│ │ └── Recommend.jsx
│ ├── mine
│ │ └── Mine.jsx
│ ├── order
│ │ └── Order.jsx
│ ├── App.jsx
│ └── App.scss
├── index.css
└── index.js
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 2.导入根组件中 并配置 hashRouter
App.jsx
import React from 'react'
import { HashRouter, Routes, Route, Link } from 'react-router-dom'
import './App.scss'
import Home from './home/Home'
import Recommend from './home/Recommend'
import Goods from './home/Goods'
import Mine from './mine/Mine'
import Order from './order/Order'
import NotFound from './404/NotFound'
//根组件
export default function App() {
return (
<div>
{/* 路由配置 */}
<HashRouter>
{/* link 导航 类似于 a标签 */}
<div className="nav">
<Link to='/home'> 首页 </Link>
<Link to="/order"> 订单 </Link>
<Link to='/mine'> 我的</Link>
</div>
{/* 定义层级路由 */}
<Routes>
{/* 默认打开 访问home index索引路由不能有子路由 */}
<Route index element={<Home/>}></Route>
<Route path='/home' element={<Home />}>
{/* 子路由定义 index 表示默认打开的子页面 */}
<Route index element={<Recommend />}></Route>
<Route path='/home/goods' element={<Goods />}></Route>
</Route>
<Route path='/order' element={<Order />}></Route>
<Route path='/mine' element={<Mine />}></Route>
{/* 404 路由 */}
<Route path='*' element={<NotFound/>}></Route>
</Routes>
</HashRouter>
</div>
)
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# 4.3 访问路由
- 通过 Link 组件访问
<Link to='/mine'> 我的</Link>
- 通过 js访问 【编程式导航】
通过 react-router-dom 的钩子函数 useNavigate 进行跳转
import React from 'react'
//导入跳转钩子函数
import {useNavigate } from 'react-router-dom';
export default function Order() {
//调用钩子函数 返回一个跳转函数
const navigate = useNavigate();
//实现跳转事件
const toGoods = ()=>{
//跳转时 不加入历史记录栈中 需额外设置replce 为true
navigate('/home/goods',{replace:true})
}
return (
<div>Order
<button onClick={toGoods}>前往商品列表</button>
</div>
)
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 4.4 跨页面传值
路由跳转携带参数(两种方式:searchParams和params)
- searchParams
传参
navigate('/goods?id=1000')
接收参数
import {useSearchParams} from 'react-router-dom'
let [params] = useSearchParams();
console.log(params.get('id'));
2
3
4
- params
传参
navigate('/goods/10000')
接受参数
import {useParams} from 'react-router-dom'
let params = useParams();
console.log(params.id);
2
3
4
配置/注册路由 的代码需要修改 App.jsx
<Route path='/home/goods/:id' element={<Goods />}></Route>
# 4.5 约定式路由 配置路由表
通过创建独立的路由文件 对层级路由数组进行配置 暴露这个路由数组【通过 react-router-dom.createHashRouter()创建】
在需要使用这个 路由表的根组件中 通过
react.RouterProvider
组件将路由表注入到对应的位置路由懒加载:通过
react.lazy()
导入页面组件,会自动对该组件进行缓存 页面组件缓存之后,第一次加载该组件时会出现异常错误,需要搭配 等待/悬而未决
react.Suspense
组件使用
<Suspense
fallback={子组件}>`路由表数据单个路由信息可以写:
id:该路由的唯一id
path: 该路由的访问路径
element: 该路由访问时加载的组件
loader: FN 函数,这个函数返回的数据 将会放在 useMatches() useMatche() 匹配路由的data中
案例:
- src/router/index.jsx
import {createHashRouter,Navigate} from 'react-router-dom'
// 导入懒加载函数
import { lazy } from 'react'
import Layout from '../views/layout/Layout'
import Login from '../views/login/Login'
// 懒加载 等待使用的时候再加载这个组件
const Home = lazy(()=>import('../views/home/Home'))
const Account = lazy(()=>import('../views/account/Account'))
const AccountAdd = lazy(()=>import('../views/account/AccountAdd'))
const AccountEdit = lazy(()=>import('../views/account/AccountEdit'))
const Goods = lazy(()=>import('../views/goods/Goods'))
const GoodsInfo = lazy(()=>import('../views/goods/GoodsInfo'))
const GoodsType = lazy(()=>import('../views/goods/GoodsType'))
import Error from '../views/error/Error'
const router = createHashRouter([
{
path:'/',
element:<Navigate to='/login'/>
},
{
path:'/login',
element:<Login />
},
{
path:'/layout',
loader:()=>({title:'首页',role:'super'}),
element:<Layout />,
children:[
{
index:true,
element:<Home />,
},
]
},
{
path:'/account',
loader:()=>({title:'账号管理',role:'super'}),
element:<Layout />,
children:[
{
index:true,
loader:()=>({title:'账号列表',role:'super'}),
element:<Account />,
},
{
path:'/account/accountAdd',
loader:()=>({title:'账号添加',role:'super'}),
element:<AccountAdd />,
},
{
path:'/account/accountEdit',
loader:()=>({title:'账号修改',role:'super'}),
element:<AccountEdit />,
},
]
},
{
path:'/goods',
element:<Layout />,
loader:()=>({title:'商品管理',role:'super'}),
children:[
{
index:true,
loader:()=>({title:'商品列表',role:'super'}),
element:<Goods />,
},
{
loader:()=>({title:'商品信息',role:'super'}),
path:'/goods/goodsInfo',
element:<GoodsInfo />,
},
{
loader:()=>({title:'商品分类',role:'super'}),
path:'/goods/goodsType',
element:<GoodsType />,
}
]
},
{
path:'*',
element:<Error />
}
])
export default router;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
- App.jsx 组件
// 导入 悬而未决的组件 和lazy 一般搭配使用 fallback属性可以传入一个组件
import { Suspense } from 'react'
// 导入 加载路由表组件 这个组件的作用 router 属性传入一个层级路由表
import { RouterProvider } from 'react-router-dom'
// 导入层级路由表
import router from './router/index'
export default function App() {
return (
<div>
{/* 因为使用了懒加载 必须使用 悬而未决 组件 等待组件加载完成之后再进行展示 */}
<Suspense fallback={<h1>loading...</h1>}>
{/* 注入路由表 */}
<RouterProvider router={router} />
</Suspense>
</div>
)
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 4.6 Hooks
useActionData (opens new window) - hooks提供前一个导航的action结果的返回值
useAsyncError (opens new window) - 返回最近的Await组件的拒绝值
useAsyncValue (opens new window) - 返回最近的Await ancestor组件的解析数据
useBeforeUnload (opens new window) - 只是window.onbeforeunload的一个辅助工具
useFetcher (opens new window) - 该功能只有在使用数据路由器时才有效
useFetchers (opens new window) - 返回一个所有inflight fetchers的数组
useFormAction (opens new window) - 在Form内部使用,以自动解决上下文中的默认action和相对action,以适应当前路由
useHref (opens new window) - 返回一个URL,可以用来链接到给定的to位置
useInRouterContext (opens new window) - 如果组件在Router的上下文中被渲染,返回true否则返回false
useLinkClickHandler (opens new window) - 返回一个点击事件处理程序用于导航
useLinkPressHandler (opens new window) - 返回自定义Link导航的按下事件处理程序
useLoaderData (opens new window) - 提供了从你的路由loader返回的值
useLocation (opens new window) - 返回当前的location对象
useMatch (opens new window) - 返回相对于当前位置的给定路径上的路由的匹配数据
useMatches (opens new window) - 返回页面上的当前路由匹配
useNavigate (opens new window) - 通常在loader和action中使用redirect
useNavigation (opens new window) - 以便在数据Mutations上建立待定的导航指标和Optimistic UI
useNavigationType (opens new window) - 返回当前的导航类型或者用户是如何来到当前页面的或者通过历史栈上的弹出、推送或替换action
useOutlet (opens new window) - 返回路由层次结构中这一层的子路由的元素
useOutletContext (opens new window) - 创 - 建你自己的context provider
useParams (opens new window) - 返回一个由当前URL的动态参数
useResolvedPath (opens new window) - 给定的to值中的pathname与当前位置的路径名进行对比
useRevalidator (opens new window)允许你以任何理由重新验证数据
useRouteError (opens new window) - 返回在action、loader或渲染过程中抛出的任何东西
useRouteLoaderData (opens new window) - 任何当前渲染的路由的数据在tree中的任何地方都可用
useRoutes (opens new window) - 返回值是一个有效的React元素
useSearchParams (opens new window) - useSearchParams的网络版
useSearchParams (RN) (opens new window) - useSearchParams的React Native版本
useSubmit (opens new window) - Form的命令式版本