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>
}
相关推荐
枫,为落叶3 小时前
【vue】设置时间格式
前端·javascript·vue.js
郝学胜-神的一滴4 小时前
Linux系统函数link、unlink与dentry的关系及使用注意事项
linux·运维·服务器·开发语言·前端·c++
昔人'4 小时前
css`text-wrap:pretty`
前端·css
勇敢di牛牛4 小时前
Vue+mockjs+Axios 案例实践
前端·javascript·vue.js
詩句☾⋆᭄南笙4 小时前
HTML列表、表格和表单
服务器·前端·html·表格·列表·表单
IT_陈寒5 小时前
Python性能翻倍的5个冷门技巧:从GIL逃逸到内存视图的实战优化指南
前端·人工智能·后端
南城巷陌5 小时前
错误边界:用componentDidCatch筑起React崩溃防火墙
前端·react.js·前端框架
FinClip5 小时前
OpenAI推出Apps SDK,你的企业App跟上了吗?
前端·app·openai
馨谙5 小时前
Linux中的管道与重定向:深入理解两者的本质区别
前端·chrome