React Router 路由基础用法讲解(上)
路由基础概念
简单来说 : 浏览器地址栏 输入URL --> 请求 --> 后端服务器
典型流程: : 前端路由拦截不同的URL -->不同的组件渲染 -->组件中可能向后端请求API接口数据-->后端路由接收不同的 URL -->不同的代码处理 ---> 响应不同的数据 (多数情况就是指API接口) -->前端渲染
1. 基本使用
第一步肯定还是用脚手架起项目
npm create vite@latest my-router
# 进入项目
cd my-router
# 安装依赖
npm install
npm install react-router-dom
# 启动开发服务器
npm run dev
1. 创建路由对象
这里我就是写一个标签试一下,element部分应该填写相关组件
const router = createBrowserRouter([
{
path : '/',
element :<h1>hello</h1>
}
])
2. 配置使用路由对象(入口文件处)
createRoot(document.getElementById('root')).render(
<StrictMode>
<RouterProvider router={router}/>
</StrictMode>,
)
2. 失败处理
1. 自定义一个错误页面 error-page.jsx
下面是官方文档写法
import { useRouteError } from "react-router-dom";
export default function ErrorPage() {
//捕获错误信息
const error = useRouteError();
console.error(error);
return (
<div id="error-page">
<h1>Oops!</h1>
<p>Sorry, an unexpected error has occurred.</p>
<p>
<i>{error.statusText || error.message}</i>
</p>
</div>
);
}
2. 应用
const router = createBrowserRouter([
{
path : '/',
element :<Root></Root>,
errorElement : <ErrorPage/>
}
])
3. 嵌套路由
首先创建一个子组件文件 src/routes/contact.jsx
接着我们进行嵌套处理,分成两步
1. 路由上嵌套
添加childern属性,原路径后拼接 contacts/随便 都可以访问到 <Contact/>
const router = createBrowserRouter([
{
path : '/',
element :<Root></Root>,
errorElement : <ErrorPage/>,
children : [{
path: "contacts/:contactId",
element : <Contact/>
}]
}
])
2. 组件上嵌套
抽象一点说就是在父组件里面挖个洞,加上<Outlet />,意思就是子组件以后放在这个位置
import { Outlet } from "react-router-dom";
export default function Root() {
return (
<>
{/* all the other elements */}
<div id="detail">
<Outlet />
</div>
</>
);
}
4. Link组件 vs a标签
<a>标签(原生 HTML)点击后不会被前端路由拦截,浏览器会直接向服务器发送 HTTP 请求,页面会 完全刷新,加载新的 HTML 页面
Link 组件(React Router 提供)点击后React Router 会拦截点击事件,更新浏览器地址栏,对应的 路由组件渲染(父路由 + 子路由)而不会刷新整个页面
5. 理解loader
先看这样一个流程
首次组件渲染(显示初始 / loading 状态)
↓
异步请求发送
↓
请求完成 → 更新 state
↓
组件重新渲染 → 显示最终数据
这里我们渲染了两次,其实如果有多个请求就会渲染多次,那么如果在路由匹配成功后组件渲染前我们就发送这个请求,会不会渲染的更快一些呢
其实是可以的
1.先将异步函数封装成loader
import { Outlet, Link } from "react-router-dom";
import { getContacts } from "../contacts";
export async function loader() {
const contacts = await getContacts();
return { contacts };
}
2.在路由中配置
这样在路由匹配成功后就会立即调用loader函数
/* other imports */
import Root, { loader as rootLoader } from "./routes/root";
//用as给来自根组件的loader取别名,因为后续可能还有其他组件的loader函数
const router = createBrowserRouter([
{
path: "/",
element: <Root />,
errorElement: <ErrorPage />,
loader: rootLoader,
children: [
{
path: "contacts/:contactId",
element: <Contact />,
},
],
},
]);
3.接收数据渲染组件
import {
Outlet,
Link,
useLoaderData,
} from "react-router-dom";
import { getContacts } from "../contacts";
/* other code */
export default function Root() {
//这里调用useLoaderData()方法获取请求得来的数据,{}作用是解构
const { contacts } = useLoaderData();
return (
<>
<div id="sidebar">
<h1>React Router Contacts</h1>
{/* other code 根据需求渲染 */}
</>
作用:获取数据 → 作为组件的初始渲染数据。
6. 理解action
在传统网页中,HTML 表单<form>是改变数据的主要方式,本质上,表单提交就像点击链接,浏览器会直接向服务器发送 HTTP 请求,页面会 完全刷新,加载新的 HTML 页面,只不过可以带数据和选择请求方式(GET / POST)
而React Router 里的<Form>组件模拟了这种 表单导航行为,但不会真的发送 HTTP 请求到服务器,它会把表单提交的数据 拦截到客户端,然后发送到 路由对应的 action(客户端逻辑处理),让页面局部更新。
来看一下如何使用action
1. 将原来的<form>用<Form>替代
<Form method="post">
<button type="submit">New</button>
</Form>
//这里没有显式写action,数据和请求方法(POST)交给 当前路由的 action
/* <Form method="post" action="/contacts/new">
<button type="submit">New</button>
</Form> */
//如果写了,那么这次提交就会被交给 /contacts/new 路由的 action。
2. 将表单提交时要用到的异步函数封装成action
export async function action() {
const contact = await createContact();
return { contact };
}
3. 在路由中配置
/* other imports */
import Root, {
loader as rootLoader,
action as rootAction,
} from "./routes/root";
const router = createBrowserRouter([
{
path: "/",
element: <Root />,
errorElement: <ErrorPage />,
loader: rootLoader,
action: rootAction,
children: [
{
path: "contacts/:contactId",
element: <Contact />,
},
],
},
]);
调用时间 : 当用户 提交 <Form> 或调用 fetcher.submit 时,并且表单 method 不是 GET(通常是 POST / PUT / PATCH / DELETE)
作用 :处理数据变更(Create / Update / Delete)。
这里提一下action和loader的区别
-
loader:
- 在页面渲染前获取数据 →
useLoaderData() - 比如编辑页面需要先拿到原始联系人信息显示在表单里。
- 在页面渲染前获取数据 →
-
action:专门处理“提交行为”(表单提交 / useSubmit / fetcher 提交)
-
它不会在进入页面时自动跑。
-
只有用户触发表单提交的时候才会执行。
-
所以进入新页面,loader会自动执行,获取数据渲染表单,而对数据进行更新操作,才会触发action,更新数据可能跳转
7. 使用URL Params 获取具体信息
其实还是通过loader
1. loader 的参数由 React Router 提供
React Router 在路由匹配时,会自动给 loader 函数传一个对象,通常包括:
{ params, // URL 参数,如 /contacts/:contactId 中的 contactId
request, // Request 对象,包含 method、formData、URL 等
context, // 可选,路由上下文 }
2. params 的来源
-
如果 URL 是
/contacts/123,路由里写了:contactId -
React Router 会把 URL 解析成:
params = { contactId: "123" };
-
loader 自动接收这个 params,就可以在函数里使用了。
3. 在loader函数里解构调用即可
export async function loader({ params }) {
const id = params.contactId;
const contact = await getContact(id);
return {contact};
}
更多推荐
所有评论(0)