React-router v7(下)

路由操作

路由的操作是由两个部分组成的:

  • loader
  • action

在平时工作中大部分都是在做增刪查改(CRUD)的操作,所以一个界面的接口过多之后就会使逻辑臃肿复杂,难以维护,所以需要使用路由的高级操作来优化代码。

loader

useLoaderData速查文档

只有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来管理表单提交的状态

useNavigation速查文档

  1. GET提交会经过以下状态:
rust 复制代码
rust
 体验AI代码助手
 代码解读
复制代码
idle -> loading -> idle
  1. 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中,大致有四种导航方式:

  1. 使用Link组件 link
  2. 使用NavLink组件 navlink
  3. 使用编程式导航useNavigate usenavigate
  4. 使用redirect重定向 redirect

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 的使用方式和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>

警告

  1. viewTransition 需要谷歌111版本才能使用,注意兼容性

  2. 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>
}
相关推荐
崔庆才丨静觅1 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60612 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了2 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅2 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅3 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅3 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment3 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅3 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊3 小时前
jwt介绍
前端
爱敲代码的小鱼4 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax