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>
}
相关推荐
BBB努力学习程序设计2 小时前
CSS Sprite技术:用“雪碧图”提升网站性能的魔法
前端·html
BBB努力学习程序设计2 小时前
CSS3渐变:用代码描绘色彩的流动之美
前端·html
冰暮流星2 小时前
css之动画
前端·css
jump6803 小时前
axios
前端
spionbo3 小时前
前端解构赋值避坑指南基础到高阶深度解析技巧
前端
用户4099322502123 小时前
Vue响应式声明的API差异、底层原理与常见陷阱你都搞懂了吗
前端·ai编程·trae
开发者小天3 小时前
React中的componentWillUnmount 使用
前端·javascript·vue.js·react.js
永远的个初学者3 小时前
图片优化 上传图片压缩 npm包支持vue(react)框架开源插件 支持在线与本地
前端·vue.js·react.js
爱吃土豆的马铃薯ㅤㅤㅤㅤㅤㅤㅤㅤㅤ3 小时前
npm i / npm install 卡死不动解决方法
前端·npm·node.js
Kratzdisteln3 小时前
【Cursor _RubicsCube Diary 1】Node.js;npm;Vite
前端·npm·node.js