路由操作
路由的操作是由两个部分组成的:
- loader
- action
在平时工作中大部分都是在做增刪查改(CRUD)
的操作,所以一个界面的接口过多之后就会使逻辑臃肿复杂,难以维护,所以需要使用路由的高级操作来优化代码。
loader
只有GET请求才会触发loader,所以适合用来获取数据
在之前的话我们是 RenderComponent(渲染组件)
-> Fetch(获取数据)
-> RenderView(渲染视图)
有了loader之后是 loader(通过fetch获取数据)
-> useLoaderData(获取数据)
-> RenderComponent(渲染组件)
javascript
ts
体验AI代码助手
代码解读
复制代码
//router/index.tsx
import { createBrowserRouter } from "react-router";
const router = createBrowserRouter([
{
path: "/",
Component: App,
loader: async () => {
const data = await response.json();
const response = await getUser(data); // [!code highlight] 获取数据
return {
data: response.list,
message: "success",
}
},
},
]);
//App.tsx
import { useLoaderData } from "react-router";
const App = () => {
const { data, message } = useLoaderData(); // [!code highlight] 获取数据
return <div>{data}</div>;
}
action
一般用于表单提交,删除,修改等操作。
useSubmit速查文档 useActionData速查文档
只有POST DELETE PATCH PUT等请求才会触发action,所以适合用来提交表单
javascript
tsx
体验AI代码助手
代码解读
复制代码
//router/index.tsx
import { createBrowserRouter } from "react-router";
const router = createBrowserRouter([
{
// path: '/index',
Component: Layout,
children: [
{
path: 'about',
Component: About,
action: async ({ request }) => {
const formData = await request.formData();
await createUser(formData); // [!code highlight] 创建用户
return {
data: table,
success: true
}
}
},
],
},
]);
//App.tsx
import { useSubmit } from 'react-router';
import { Card, Form, Input, Button } from 'antd';
export default function About() {
const submit = useSubmit();
return <Card>
<Form onFinish={(values) => {
submit(values, { method: 'post'}) // [!code highlight] 提交表单
}}>
<Form.Item name='name' label='姓名'>
<Input />
</Form.Item>
<Form.Item name='age' label='年龄'>
<Input />
</Form.Item>
<Button type='primary' htmlType='submit'>提交</Button>
</Form>
</Card>;
}
状态变更
我们可以配合useNavigation
来管理表单提交的状态
- GET提交会经过以下状态:
rust
rust
体验AI代码助手
代码解读
复制代码
idle -> loading -> idle
- POST提交会经过以下状态:
rust
rust
体验AI代码助手
代码解读
复制代码
idle -> submitting ->loading -> idle
所以我们可以根据这些状态来控制disabled
loading
等行为
javascript
tsx
体验AI代码助手
代码解读
复制代码
import { useNavigation, useSubmit } from "react-router";
const submit = useSubmit();
const navigation = useNavigation();
return (
<div>
{navigation.state === 'loading' && <div>loading...</div>}
<button disabled={navigation.state === 'submitting'}>提交</button>
</div>
)
导航
在React-router V7中,大致有四种导航方式:
- 使用
Link
组件 link - 使用
NavLink
组件 navlink - 使用编程式导航
useNavigate
usenavigate - 使用
redirect
重定向 redirect
Link
Link
组件是一个用于导航到其他页面的组件,他会被渲染成一个特殊的<a>
标签,跟传统a标签不同的是,他不会刷新页面,而是会通过router管理路由表。
使用
javascript
tsx
体验AI代码助手
代码解读
复制代码
import { Link } from "react-router";
export default function App() {
return (
<Link to="/about">About</Link>
)
}
参数
to
:要导航到的路径replace
:是否替换当前路径state
:要传递给目标页面的状态relative
:相对于当前路径的导航方式reloadDocument
:是否重新加载页面preventScrollReset
:是否阻止滚动位置重置viewTransition
:是否启用视图过渡
to
to
属性是一个字符串,表示要导航到的路径。
ini
tsx
体验AI代码助手
代码解读
复制代码
<Link to="/about">About</Link>
replace
replace
属性是一个布尔值,表示是否替换当前路径,如果为true
,则导航不会在浏览器历史记录中创建新的条目,而是替换当前条目。
ini
tsx
体验AI代码助手
代码解读
复制代码
<Link replace to="/about">About</Link>
state
state
属性是一个对象,可以把参数传递给目标页面。
javascript
tsx
体验AI代码助手
代码解读
复制代码
<Link state={{ from: "home" }} to="/about">About</Link>
// 在目标页面获取状态
import { useLocation } from "react-router";
export default function App() {
const location = useLocation();
console.log(location.state);
return <div>Location: {location.state.from}</div>;
}
relative
relative
属性是一个字符串,表示相对于当前路径的导航方式,默认的方式是绝对路径,如果想要使用相对路径,可以设置为path
。
javascript
tsx
体验AI代码助手
代码解读
复制代码
//默认是绝对路径
<Link relative="route" to="/about">About</Link>
//使用相对路径
<Link relative="path" to="../about">About</Link>
//例如当前的路由是/index/home,那么使用绝对路径导航到/about,会变成/about
<Link to="/about">About</Link>
//可以使用相对路径导航到/index/about
<Link relative="path" to="../about">About</Link>
reloadDocument
reloadDocument
属性是一个布尔值,表示是否重新加载页面。
ini
tsx
体验AI代码助手
代码解读
复制代码
<Link reloadDocument to="/about">About</Link>
preventScrollReset
preventScrollReset
属性是一个布尔值,表示是否阻止滚动位置重置。
ini
tsx
体验AI代码助手
代码解读
复制代码
<Link preventScrollReset to="/about">About</Link>
viewTransition
viewTransition
属性是一个布尔值,表示是否启用视图过渡,自动增加页面跳转的动画效果。
ini
tsx
体验AI代码助手
代码解读
复制代码
<Link viewTransition to="/about">About</Link>
NavLink
NavLink
的使用方式和Link
组件类似,但是NavLink
组件可以实现路由的激活状态。
使用
javascript
tsx
体验AI代码助手
代码解读
复制代码
import { NavLink } from "react-router";
export default function App() {
return (
<NavLink to="/about">About</NavLink>
)
}
参数(和Link组件的参数类似)
to
:要导航到的路径replace
:是否替换当前路径state
:要传递给目标页面的状态relative
:相对于当前路径的导航方式reloadDocument
:是否重新加载页面preventScrollReset
:是否阻止滚动位置重置viewTransition
:是否启用视图过渡
to
to
属性是一个字符串,表示要导航到的路径。
ini
tsx
体验AI代码助手
代码解读
复制代码
<NavLink to="/about">About</NavLink>
replace
replace
属性是一个布尔值,表示是否替换当前路径,如果为true
,则导航不会在浏览器历史记录中创建新的条目,而是替换当前条目。
ini
tsx
体验AI代码助手
代码解读
复制代码
<NavLink replace to="/about">About</NavLink>
state
state
属性是一个对象,可以把参数传递给目标页面。
javascript
tsx
体验AI代码助手
代码解读
复制代码
<NavLink state={{ from: "home" }} to="/about">About</NavLink>
// 在目标页面获取状态
import { useLocation } from "react-router";
export default function App() {
const location = useLocation();
console.log(location.state);
return <div>Location: {location.state.from}</div>;
}
relative
relative
属性是一个字符串,表示相对于当前路径的导航方式,默认的方式是绝对路径,如果想要使用相对路径,可以设置为path
。
javascript
tsx
体验AI代码助手
代码解读
复制代码
//默认是绝对路径
<NavLink relative="route" to="/about">About</NavLink>
//使用相对路径
<NavLink relative="path" to="../about">About</NavLink>
//例如当前的路由是/index/home,那么使用绝对路径导航到/about,会变成/about
<NavLink to="/about">About</NavLink>
//可以使用相对路径导航到/index/about
<NavLink relative="path" to="../about">About</NavLink>
reloadDocument
reloadDocument
属性是一个布尔值,表示是否重新加载页面。
ini
tsx
体验AI代码助手
代码解读
复制代码
<NavLink reloadDocument to="/about">About</NavLink>
preventScrollReset
preventScrollReset
属性是一个布尔值,表示是否阻止滚动位置重置。
ini
tsx
体验AI代码助手
代码解读
复制代码
<NavLink preventScrollReset to="/about">About</NavLink>

viewTransition
viewTransition
属性是一个布尔值,表示是否启用视图过渡,自动增加页面跳转的动画效果。
ini
tsx
体验AI代码助手
代码解读
复制代码
<NavLink viewTransition to="/about">About</NavLink>
区别
Navlink 会经过以下三个状态的转换,而Link不会,所以Navlink就是一个link的增强版。
active
:激活状态(当前路由和to属性匹配)pending
:等待状态(loader有数据需要加载)transitioning
:过渡状态(通过viewTransition属性触发)
active自动激活
Navlink 会根据当前路由和to属性是否匹配,自动激活。
react-router会为其自动添加样式
css
css
体验AI代码助手
代码解读
复制代码
a.active {
color: red;
}
a.pending {
animate: pulse 1s infinite;
}
a.transitioning {
/* css transition is running */
}
如果不喜欢写样式也可以直接用style属性来设置
javascript
tsx
体验AI代码助手
代码解读
复制代码
<NavLink viewTransition style={({isActive,isPending,isTransitioning})=>{
return {
marginRight:'10px',
color:isActive?'red':'blue',
backgroundColor:isPending?'yellow':'transparent',
}
}} to="/index/about">About</NavLink>
警告
-
viewTransition 需要谷歌111版本才能使用,注意兼容性
-
pending只有数据模式,和框架模式才能使用,声明式路由不能使用
useNavigate
useNavigate
是一个 React-router 的钩子,用于编程式导航,的路由跳转。
例如倒计时结束后,自动返回跳转等,因为这种操作属于逻辑性操作,这时候组件方式的跳转就不合适了,这时候就需要使用编程式跳转。
javascript
tsx
体验AI代码助手
代码解读
复制代码
import { useNavigate } from 'react-router';
const navigate = useNavigate();
setTimeout(() => {
navigate('/home');
}, 1000);
参数
跟Link组件的参数类似
-
第一个参数: to跳转的路由
navigate(to)
-
第二个参数: options配置对象
navigate(to,options)
- replace: 是否替换当前路由
- state: 传递的数据
- relative: 相对路径
- preventScrollReset: 是否阻止滚动重置
to
javascript
tsx
体验AI代码助手
代码解读
复制代码
import { useNavigate } from 'react-router'; // 导入useNavigate
const navigate = useNavigate(); // 获取navigate函数
navigate('/home'); // 跳转路由
options-replace
跳转页面的时候,是否替换当前路由
php
tsx
体验AI代码助手
代码解读
复制代码
navigate('/home',{replace:true});
options-state
传递数据,在跳转的页面中使用通过useLocation
的state属性获取
php
tsx
体验AI代码助手
代码解读
复制代码
navigate('/home',{state:{name:'张三'}});
options-relative
跳转的方式,默认是绝对路径,如果想要使用相对路径,需要设置为relative:'path'
具体细节查看
link-relative
php
tsx
体验AI代码助手
代码解读
复制代码
navigate('/home',{relative:'path'});
options-preventScrollReset
跳转页面的时候,是否阻止滚动重置
具体细节查看
link-preventScrollReset
php
tsx
体验AI代码助手
代码解读
复制代码
navigate('/home',{preventScrollReset:true});
options-viewTransition
跳转页面的时候,是否启用视图过渡,自动增加页面跳转的动画效果。
php
tsx
体验AI代码助手
代码解读
复制代码
navigate('/home',{viewTransition:true});
redirect
redirect 是用于重定向,通常用于loader
中,当loader
返回redirect
的时候,会自动重定向到redirect
指定的路由。
案例以及用法
权限验证,例如这个路由需要登录才能访问,如果未登录则重定向到登录页。
javascript
tsx
体验AI代码助手
代码解读
复制代码
import { redirect } from "react-router";
{
path: "/home",
loader: async ({request}) => {
const isLogin = await checkLogin();
if(!isLogin) return redirect('/login');
return {
data: 'home'
}
}
}
边界处理
边界处理包含了错误处理
,ErrorBoundary
404页面等错误处理
404页面处理
404页面指的是当React-router路由匹配不到时,显示的页面,例如我们的路由是/home,/about,当你去跳转到一个不存在的路由比如/aaa时,就会显示404页面。 不过react-router自带的404页面太丑了,更多的时候我们需要自定义404页面。
配置
- 使用
*
作为通配符,当路由匹配不到时,显示404页面 - 使用
Component: NotFound
作为404页面组件
php
ts
体验AI代码助手
代码解读
复制代码
const router = createBrowserRouter([
{
path: '/index',
Component: Layout,
children: [
{
path: 'home',
Component: Home,
},
{
path: 'about',
Component: About,
},
],
},
{
path: '*', // [!code highlight] 通配符,当路由匹配不到时,显示404页面
Component: NotFound, // [!code highlight] 404页面组件
},
]);
404.tsx
less
tsx
体验AI代码助手
代码解读
复制代码
import { Link } from 'react-router'
export default function NotFound() {
return (
<div style={{
height: '100vh',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
background: '#f5f5f5'
}}>
<h1 style={{ fontSize: 96, color: '#1890ff', margin: 0 }}>404</h1>
<p style={{ fontSize: 24, color: '#888', margin: '16px 0 0 0' }}>
抱歉,您访问的页面不存在
</p>
<Link
to="/"
style={{
marginTop: 32,
color: '#1890ff',
fontSize: 18,
textDecoration: 'underline'
}}
>
返回首页
</Link>
</div>
)
}

ErrorBoundary
ErrorBoundary是用于捕获路由loader或action的错误,并进行处理。
如果loader或action抛出错误,会调用ErrorBoundary组件。
php
tsx
体验AI代码助手
代码解读
复制代码
import NotFound from '../layout/404'; // 404页面组件
import Error from '../layout/error'; // 错误处理组件
const router = createBrowserRouter([
{
path: '/index',
Component: Layout,
children: [
{
path: 'home',
Component: Home,
ErrorBoundary: Error, //如果组件抛出错误,会调用ErrorBoundary组件
},
{
path: 'about',
loader: async () => {
//throw new Response('Not Found', { status: 404, statusText: 'Not Found' }); 可以返回Response对象
//也可以返回json等等
throw {
message: 'Not Found',
status: 404,
statusText: 'Not Found',
data: '132131',
}
},
Component: About,
ErrorBoundary: Error, //如果loader或action抛出错误,会调用ErrorBoundary组件
},
],
},
{
path: '*',
Component: NotFound,
},
]);
并且返回的错误信息可以通过一个hooksuseRouteError
获取到
error.tsx
javascript
tsx
体验AI代码助手
代码解读
复制代码
import { useRouteError } from 'react-router'
export default function Error() {
const error = useRouteError()
return <div>{error.message}</div>
}