当前位置: 首页 > news >正文

React 第五十九节 Router中 createBrowserRouter使用详解与案例分析

前言

createBrowserRouterReact Router v6.4+ 中用于创建浏览器端路由的核心函数,它引入了数据路由(data routing)的概念,提供了更强大的路由功能,如数据预加载、表单处理等。

一、createBrowserRouter 的主要用途

  1. 创建路由配置:定义应用程序的路由结构
  2. 数据预加载:在渲染组件前获取所需数据
  3. 表单处理:处理表单提交和数据变更
  4. 错误处理:提供路由级错误边界
  5. 嵌套路由:支持复杂布局和嵌套路由结构
  6. 延迟加载:实现代码分割和按需加载

二、完整代码示例

2.1、 基础路由配置

// src/main.jsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import {createBrowserRouter,RouterProvider,Link,Outlet
} from 'react-router-dom';// 页面组件
function Home() {return (<div className="page"><h1>首页</h1><p>欢迎来到我们的网站!</p><nav className="page-nav"><Link to="/products" className="nav-link">产品列表</Link><Link to="/about" className="nav-link">关于我们</Link></nav></div>);
}function About() {return (<div className="page"><h1>关于我们</h1><p>我们是一家专注于前端技术的公司。</p><Link to="/" className="back-link">返回首页</Link></div>);
}// 产品列表组件
function Products() {return (<div className="page"><h1>产品列表</h1><ul className="product-list"><li><Link to="/products/1">产品 1</Link></li><li><Link to="/products/2">产品 2</Link></li><li><Link to="/products/3">产品 3</Link></li></ul><Link to="/" className="back-link">返回首页</Link></div>);
}// 布局组件
function RootLayout() {return (<div className="app"><header className="app-header"><h1 className="logo">React Router 示例</h1><nav className="main-nav"><Link to="/" className="nav-item">首页</Link><Link to="/about" className="nav-item">关于</Link><Link to="/products" className="nav-item">产品</Link></nav></header><main className="app-content">{/* 子路由将在这里渲染 */}<Outlet /></main><footer className="app-footer"><p>© 2023 React Router 示例应用</p></footer></div>);
}// 创建路由配置
const router = createBrowserRouter([{path: "/",element: <RootLayout />,children: [{index: true, // 匹配根路径element: <Home />},{path: "about",element: <About />},{path: "products",element: <Products />}]}
]);// 渲染应用
ReactDOM.createRoot(document.getElementById('root')).render(<React.StrictMode><RouterProvider router={router} /></React.StrictMode>
);

2.2、 高级功能:数据加载和表单处理

// 添加以下代码到 main.jsx// 产品详情组件(带数据加载)
import { useLoaderData, useParams, Form, redirect } from 'react-router-dom';function ProductDetail() {const product = useLoaderData();return (<div className="page"><h1>{product.name}</h1><p className="product-description">{product.description}</p><p className="product-price">价格: ¥{product.price}</p><div className="product-actions"><Link to="/products" className="back-link">返回产品列表</Link>{/* 删除产品表单 */}<Form method="post" action={`/products/${product.id}/delete`}><button type="submit" className="delete-btn">删除产品</button></Form></div><div className="reviews-section"><h2>用户评价</h2>{/* 添加评价表单 */}<Form method="post" action={`/products/${product.id}/review`}><div className="form-group"><label htmlFor="rating">评分:</label><select id="rating" name="rating" required><option value="5">5</option><option value="4">4</option><option value="3">3</option><option value="2">2</option><option value="1">1</option></select></div><div className="form-group"><label htmlFor="comment">评论:</label><textarea id="comment" name="comment" required></textarea></div><button type="submit" className="submit-btn">提交评价</button></Form></div></div>);
}// 产品数据加载器
export async function productLoader({ params }) {// 模拟API请求const products = {1: { id: 1, name: 'React 教程', description: '深入学习 React 框架', price: 99 },2: { id: 2, name: 'Node.js 实战', description: '构建高性能后端应用', price: 129 },3: { id: 3, name: 'TypeScript 指南', description: '掌握类型安全的JavaScript', price: 89 }};// 模拟延迟await new Promise(resolve => setTimeout(resolve, 500));const product = products[params.productId];if (!product) {throw new Response('产品未找到', { status: 404 });}return product;
}// 删除产品操作
export async function deleteProductAction({ params }) {// 在实际应用中,这里会调用API删除产品console.log(`删除产品 ${params.productId}`);// 重定向到产品列表return redirect('/products');
}// 添加评价操作
export async function addReviewAction({ request, params }) {const formData = await request.formData();const review = {productId: params.productId,rating: formData.get('rating'),comment: formData.get('comment'),date: new Date().toISOString()};// 在实际应用中,这里会保存评价到数据库console.log('添加评价:', review);// 重定向回产品详情页return redirect(`/products/${params.productId}`);
}// 错误页面组件
function ErrorPage() {return (<div className="error-page"><h1>出错了!</h1><p>抱歉,您访问的页面不存在或发生错误。</p><Link to="/" className="back-link">返回首页</Link></div>);
}// 更新路由配置
const router = createBrowserRouter([{path: "/",element: <RootLayout />,errorElement: <ErrorPage />, // 全局错误边界children: [{index: true,element: <Home />},{path: "about",element: <About />},{path: "products",element: <Products />,children: [{path: ":productId",element: <ProductDetail />,loader: productLoader, // 数据预加载errorElement: <div className="error">产品加载失败</div>, // 特定路由错误边界children: [{path: "delete",action: deleteProductAction // 删除操作},{path: "review",action: addReviewAction // 添加评价操作}]}]}]}
]);

2.3、 延迟加载(代码分割)

// 更新路由配置,添加延迟加载
const router = createBrowserRouter([{path: "/",element: <RootLayout />,errorElement: <ErrorPage />,children: [{index: true,element: <Home />},{path: "about",// 延迟加载关于页面lazy: () => import("./routes/About")},{path: "products",element: <Products />,children: [{path: ":productId",// 延迟加载产品详情lazy: async () => {const { default: ProductDetail } = await import("./routes/ProductDetail");return { Component: ProductDetail,loader: productLoader};},errorElement: <div className="error">产品加载失败</div>,children: [// ...操作路由]}]},{path: "dashboard",// 延迟加载仪表盘lazy: () => import("./routes/Dashboard")}]}
]);

三、createBrowserRouter 核心功能详解

3.1、 路由配置结构

createBrowserRouter 接收一个路由对象数组,每个对象包含:

  1. path:路由路径
  2. element:渲染的组件
  3. loader:数据加载函数
  4. action:表单处理函数
  5. errorElement:错误边界组件
  6. children:嵌套路由
const router = createBrowserRouter([{path: "/",element: <Layout />,children: [{ index: true, element: <Home /> },{ path: "about", element: <About /> }]}
]);

3.2、 数据加载(loader

在组件渲染前获取数据:

{path: "products/:id",element: <ProductDetail />,loader: async ({ params }) => {const response = await fetch(`/api/products/${params.id}`);if (!response.ok) throw new Error('产品未找到');return response.json();}
}

在组件中使用数据:

import { useLoaderData } from 'react-router-dom';function ProductDetail() {const product = useLoaderData();return <h1>{product.name}</h1>;
}

3.3、 表单处理(action

处理表单提交:

{path: "products/:id/review",action: async ({ request, params }) => {const formData = await request.formData();const review = Object.fromEntries(formData);// 保存评价await saveReview(params.id, review);// 重定向回产品页return redirect(`/products/${params.id}`);}
}

在表单组件中使用:

import { Form } from 'react-router-dom';function ReviewForm() {return (<Form method="post" action="/products/123/review">{/* 表单字段 */}</Form>);
}

3.4、 错误处理

{path: "/",element: <Layout />,errorElement: <ErrorBoundary />, // 全局错误边界children: [{path: "products/:id",element: <ProductDetail />,errorElement: <ProductError />, // 特定路由错误边界loader: productLoader}]
}

在错误边界组件中获取错误信息:

import { useRouteError } from 'react-router-dom';function ErrorBoundary() {const error = useRouteError();return <div>错误: {error.message}</div>;
}

3.5、 路由导航

import { Link, NavLink, useNavigate } from 'react-router-dom';// 创建链接
<Link to="/about">关于我们</Link>// 活动链接样式
<NavLink to="/products"className={({ isActive }) => isActive ? 'active' : ''}
>产品
</NavLink>// 编程式导航
function Home() {const navigate = useNavigate();return (<button onClick={() => navigate('/about')}>前往关于页面</button>);
}

四、createBrowserRouter 与传统路由对比

在这里插入图片描述

五、最佳实践

  1. 合理组织路由结构:使用嵌套路由处理复杂布局

  2. 利用代码分割:延迟加载非关键路由

  3. 统一错误处理:设置全局和局部错误边界

  4. 优化数据加载:

    使用Promise.all并行加载数据

    实现数据缓存

  5. 安全考虑:

    验证用户输入

    处理敏感数据

  6. 性能优化:

    使用defer API处理慢速加载

    实现加载状态指示器

总结

createBrowserRouter 是 React Router v6.4+ 中推荐的浏览器端路由创建方式,它通过数据驱动的路由模型提供了更强大的功能:

  1. 声明式路由配置:集中管理所有路由规则
  2. 内置数据加载:在渲染前预取所需数据
  3. 高效表单处理:简化表单提交逻辑
  4. 精细错误控制:路由级错误边界
  5. 无缝代码分割:优化应用性能

通过结合 RouterProvider 使用,可以构建功能丰富性能优越的现代 React 应用程序,特别适合需要复杂数据管理状态同步的应用场景。

http://www.xdnf.cn/news/977617.html

相关文章:

  • Etcd数据持久化机制:WAL与Snapshot解析
  • python数据结构和算法(5)
  • zset类型
  • Bright Data网页抓取工具实战:BOSS直聘爬虫 + PandasAI分析洞察前端岗位市场趋势
  • 深度学习小项目合集之图像分割识别-视频介绍下自取
  • ThreadLocal实现原理
  • SpringBoot前后台交互 -- 登录功能实现(拦截器+异常捕获器)
  • 音频导入规范
  • 大模型实战篇之ChatGPT(国内可以用)一、实现连续对话智能体
  • 【Linux shell】条件判断和流程控制
  • DL00124-基于YOLOv12深度学习的棉花叶片病害检测含完整数据集
  • BERT 模型微调与传统机器学习的对比
  • uniapp音乐播放createInnerAudioContext
  • 零基础实战:云开发家政维修小程序搭建指南
  • UniApp组件封装,2025年最新HarmonyOS鸿蒙模块化开发项目式教程
  • vue3 + element plus 实现表格列头、行的添加及拖动换位
  • vue前端面试题——记录一次面试当中遇到的题(1)
  • element-ui 的el-table,多选翻页后,之前选择的数据丢失问题处理
  • 黑马教程强化day2-1
  • JAVA毕业设计227—基于SpringBoot+hadoop+spark+Vue的大数据房屋维修系统(源代码+数据库)
  • Linux 文件内容的查询与统计
  • xilinx的gt的ALIGN_COMMA_WORD设置的作用
  • UE5 学习系列(五)导入贴图资产
  • 纯血Harmony NETX 5小游戏实践:2048(附源文件)
  • vuetify、nuxt报错lh.at is not a functionlh.at‘ is undefined
  • R语言 | 如何使用R书写html文档?
  • 打造超轻量的仿chatgpt的AI聊天应用
  • IDEA 连接 Docker 一键打镜像
  • LHM深度技术解析:基于多模态Transformer的单图秒级可动画3D人体重建模型
  • 2025.06.11【Ribo-seq】|根据注释文件获取外显子及ORF序列