React第六十节 Router中createHashRouter的具体使用详解及案例分析
前言
createHashRouter
是 React Router
提供的一种特殊路由器,它使用 URL 的哈希部分(#)
来处理客户端路由。
这种路由方式特别适用于静态网站托管服务(如 GitHub Pages)或无法配置服务器以支持 HTML5 History API
的场景。
一、createHashRouter 的主要用途
- 无服务器配置要求:不需要服务器端重写规则
- 静态网站兼容:完美适配 GitHub Pages 等静态托管服务
- 旧浏览器支持:兼容不支持 HTML5 History API 的浏览器
- 简单部署:避免处理服务器配置问题
- 本地开发便利:在本地文件系统上也能正常工作
二、createHashRouter 与 createBrowserRouter 的关键区别
三、createHashRouter
完整代码示例
3.1、 基础路由配置
// src/main.jsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import {createHashRouter,RouterProvider,Link,Outlet,useLocation
} from 'react-router-dom';// 页面组件
function Home() {return (<div className="page home"><h1>首页</h1><p>欢迎使用哈希路由示例应用</p><div className="page-nav"><Link to="/about" className="nav-link">关于我们</Link><Link to="/products" className="nav-link">产品列表</Link></div></div>);
}function About() {return (<div className="page about"><h1>关于我们</h1><p>我们是一家专注于前端技术的公司</p><Link to="/" className="back-link">返回首页</Link></div>);
}// 布局组件
function RootLayout() {const location = useLocation();return (<div className="app"><header className="app-header"><h1 className="logo">哈希路由示例</h1><div className="url-display">当前路由: <code>{location.pathname || '/'}</code></div><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>当前使用: <code>createHashRouter</code> | © 2023 React Router 示例</p></footer></div>);
}// 创建哈希路由配置
const router = createHashRouter([{path: "/",element: <RootLayout />,children: [{index: true,element: <Home />},{path: "about",element: <About />},{path: "products",element: <ProductsList />,children: [{path: ":productId",element: <ProductDetail />}]}]}
]);// 产品列表组件
function ProductsList() {const products = [{ id: 1, name: 'React 教程', price: 99 },{ id: 2, name: 'Node.js 实战', price: 129 },{ id: 3, name: 'TypeScript 指南', price: 89 }];return (<div className="page products"><h1>产品列表</h1><div className="products-grid">{products.map(product => (<div key={product.id} className="product-card"><h3><Link to={`/products/${product.id}`}>{product.name}</Link></h3><p>价格: ¥{product.price}</p></div>))}</div><Link to="/" className="back-link">返回首页</Link></div>);
}// 产品详情组件
function ProductDetail() {const { productId } = useParams();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 }};const product = products[productId];if (!product) {return (<div className="error"><h2>产品未找到</h2><p>没有找到ID为 {productId} 的产品</p><Link to="/products" className="back-link">返回产品列表</Link></div>);}return (<div className="page product-detail"><h1>{product.name}</h1><p className="description">{product.description}</p><p className="price">价格: ¥{product.price}</p><Link to="/products" className="back-link">返回产品列表</Link></div>);
}// 渲染应用
ReactDOM.createRoot(document.getElementById('root')).render(<React.StrictMode><RouterProvider router={router} /></React.StrictMode>
);
3.2、 带数据加载的高级示例
// 在 main.jsx 中添加以下内容
import { useLoaderData } from 'react-router-dom';// 创建模拟API函数
async function fetchProduct(productId) {// 模拟API延迟await new Promise(resolve => setTimeout(resolve, 500));const products = {1: { id: 1, name: 'React 教程', description: '深入学习 React 框架', price: 99, reviews: 24 },2: { id: 2, name: 'Node.js 实战', description: '构建高性能后端应用', price: 129, reviews: 18 },3: { id: 3, name: 'TypeScript 指南', description: '掌握类型安全的JavaScript', price: 89, reviews: 32 }};return products[productId] || null;
}// 更新产品详情组件使用加载器
function ProductDetail() {const product = useLoaderData();if (!product) {return (<div className="error"><h2>产品未找到</h2><p>请求的产品不存在</p><Link to="/products" className="back-link">返回产品列表</Link></div>);}return (<div className="page product-detail"><h1>{product.name}</h1><p className="description">{product.description}</p><div className="product-meta"><span className="price">价格: ¥{product.price}</span><span className="reviews">评价: {product.reviews} 条</span></div><Link to="/products" className="back-link">返回产品列表</Link></div>);
}// 添加产品加载器
async function productLoader({ params }) {const product = await fetchProduct(params.productId);if (!product) {throw new Response('Product Not Found', { status: 404 });}return product;
}// 更新路由配置
const router = createHashRouter([{path: "/",element: <RootLayout />,children: [// ...其他路由{path: "products",element: <ProductsList />,children: [{path: ":productId",element: <ProductDetail />,loader: productLoader,errorElement: <div className="error">产品加载失败</div>}]}]}
]);
3.3、 表单处理示例
// 添加联系表单页面
function Contact() {return (<div className="page contact"><h1>联系我们</h1><ContactForm /><Link to="/" className="back-link">返回首页</Link></div>);
}// 联系表单组件
function ContactForm() {return (<form className="contact-form" method="post" action="/contact"><div className="form-group"><label htmlFor="name">姓名</label><input type="text" id="name" name="name" required placeholder="请输入您的姓名"/></div><div className="form-group"><label htmlFor="email">邮箱</label><input type="email" id="email" name="email" required placeholder="请输入您的邮箱"/></div><div className="form-group"><label htmlFor="message">留言</label><textarea id="message" name="message" required rows="5"placeholder="请输入您的留言内容"></textarea></div><button type="submit" className="submit-btn">提交</button></form>);
}// 联系表单处理器
async function contactAction({ request }) {const formData = await request.formData();const data = Object.fromEntries(formData);// 在实际应用中,这里会发送数据到服务器console.log('收到联系表单:', data);// 显示成功消息return { success: true, message: '感谢您的留言,我们会尽快回复!' };
}// 更新路由配置
const router = createHashRouter([{path: "/",element: <RootLayout />,children: [// ...其他路由{path: "contact",element: <Contact />,action: contactAction}]}
]);
四、createHashRouter
核心特性详解
4.1、哈希路由工作原理
哈希路由使用 URL 的哈希部分(# 之后的内容)来管理应用状态:
text
http://example.com/#/about
http://example.com/#/products/123
- 哈希部分的变化不会触发页面刷新
- 服务器只接收
http://example.com/
请求 - 路由完全在客户端处理
4.2、 路由配置
配置方式与 createBrowserRouter
相同:
const router = createHashRouter([{path: "/",element: <Layout />,children: [{ index: true, element: <Home /> },{ path: "about", element: <About /> },{ path: "contact", element: <Contact /> }]}
]);
4.3、 数据加载(loader
)
{path: "products/:id",element: <ProductDetail />,loader: async ({ params }) => {const response = await fetch(`/api/products/${params.id}`);return response.json();}
}
4.4、 表单处理(action
)
{path: "contact",element: <Contact />,action: async ({ request }) => {const formData = await request.formData();// 处理表单数据return redirect('/thank-you');}
}
4.5、 错误处理
{path: "/",element: <Layout />,errorElement: <GlobalError />,children: [{path: "products/:id",element: <ProductDetail />,errorElement: <ProductError />,loader: productLoader}]
}
4.6、 编程式导航
import { useNavigate } from 'react-router-dom';function LoginButton() {const navigate = useNavigate();const handleLogin = () => {// 执行登录逻辑...navigate('/dashboard');};return <button onClick={handleLogin}>登录</button>;
}
五、最佳实践
5.1、 部署到 GitHub Pages
- 创建 React 应用:
npx create-react-app my-app
- 安装 React Router:
npm install react-router-dom
- 配置哈希路由
- 在 package.json 中添加:
json
"homepage": "https://<username>.github.io/<repo-name>",
"scripts": {"predeploy": "npm run build","deploy": "gh-pages -d build"
}
- 安装
gh-pages:npm install gh-pages --save-dev
- 部署:
npm run deploy
5.2、 处理深链接
由于哈希路由不需要服务器配置,深链接可以直接工作:
text
https://username.github.io/repo/#/products/123
5.3、 SEO 优化策略
虽然哈希路由对 SEO 不友好,但可以采取以下策略:
- 使用服务端渲染(SSR)替代
- 添加预渲染(如使用 react-snap)
- 提供静态元数据:
html
<meta name="description" content="产品详情页">
5.4、 性能优化
代码分割:
const ProductDetail = React.lazy(() => import('./ProductDetail'));{path: "products/:id",element: (<React.Suspense fallback={<div>加载中...</div>}><ProductDetail /></React.Suspense>)
}
数据预加载:
<Link to="/products/123" onMouseEnter={() => preloadProductData(123)}
>产品详情
</Link>
六、createHashRouter
使用场景推荐
- GitHub Pages 项目:个人作品集、项目文档
- 静态网站:营销页面、活动页面
- 本地文件协议:file:// 协议下的应用
- 浏览器扩展:Chrome/Firefox 扩展的弹出页面
- 临时演示:快速分享原型演示
- 旧浏览器支持:需要兼容 IE9 等旧浏览器
总结
createHashRouter
是 React Router
提供的一种特殊路由解决方案,它通过 URL 的哈希部分实现客户端路由
,
主要特点包括:
- 无需服务器配置:适用于静态托管环境
- 广泛兼容性:支持所有现代和旧版浏览器
- 简单易用:与标准路由 API 完全兼容
- 快速部署:特别适合 GitHub Pages 等平台
虽然哈希路由在 URL 美观性和 SEO 方面存在不足,但在以下场景中它是理想选择:
-
静态网站托管(GitHub Pages、Netlify、Vercel 等)
-
无法配置服务器重定向规则的环境
-
需要支持旧版浏览器的应用
-
本地文件系统运行的应用程序
通过结合 React Router
的数据加载、表单处理和错误边界功能,createHashRouter
可以构建功能完善的单页应用,同时享受简单部署的便利性。