前言
StaticRouterProvider
是 React Router v6.4+
中用于服务端渲染(SSR)
的核心组件。
它允许在服务器端处理路由匹配、数据加载和错误处理,然后将结果传递给客户端进行 hydration。
一、StaticRouterProvider 的主要用途
- 服务端渲染支持:在服务器端处理路由匹配和数据加载
- 数据预取:在客户端渲染前获取所需数据
- 状态同步:保持服务器和客户端渲染状态一致
- 错误处理:在服务器端处理路由级错误
- SEO优化:提供完整的HTML给搜索引擎
二、服务器端实现 (Node.js/Express
)
javascript
// server.js
import express from 'express';
import React from 'react';
import ReactDOMServer from 'react-dom/server';
import { renderServerSide } from './src/main.jsx';
const app = express();
const port = 3000;
// 静态文件服务
app.use(express.static('dist'));
// 处理所有路由
app.get('*', async (req, res) => {
try {
// 渲染服务器端内容
const { html: appHtml, context } = await renderServerSide(req.url);
// 如果返回重定向,直接处理
if (context instanceof Response && context.headers.get('Location')) {
return res.redirect(302, context.headers.get('Location'));
}
// 渲染完整HTML
const html = `
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>React Router SSR 示例</title>
<link rel="stylesheet" href="/styles.css">
<script>
// 将服务器端状态传递给客户端
window.__staticRouterHydrationData = ${JSON.stringify(context)};
</script>
</head>
<body>
<div id="root">${ReactDOMServer.renderToString(appHtml)}</div>
<script src="/client-bundle.js"></script>
</body>
</html>
`;
res.status(200).send(html);
} catch (err) {
console.error('服务器渲染错误:', err);
res.status(500).send('服务器错误');
}
});
app.listen(port, () => {
console.log(`服务器运行在 http://localhost:${port}`);
});
三、StaticRouterProvider 关键特性详解
3.1、 核心工作流程
创建静态处理器 :createStaticHandler(routes)
处理请求 :handler.query(request)
创建静态路由 :createStaticRouter(handler.dataRoutes, context)
渲染组件 :<StaticRouterProvider router={router} context={context} />
3.2、 服务器端数据加载
javascript
// 在路由配置中添加loader
const routes = createRoutesFromElements(
<Route path="/products/:id" element={<ProductDetail />}
loader={async ({ params }) => {
// 从API获取产品数据
const response = await fetch(`/api/products/${params.id}`);
if (!response.ok) throw new Error('产品未找到');
return response.json();
}}
/>
);
// 在组件中使用数据
function ProductDetail() {
const product = useLoaderData();
return (
<div>
<h1>{product.name}</h1>
<p>{product.description}</p>
</div>
);
}
3.3、 错误处理
javascript
// 在路由配置中添加错误边界
<Route path="/products/:id"
element={<ProductDetail />}
loader={async ({ params }) => { /* ... */ }}
errorElement={<ProductError />} // 产品详情错误页面
/>
// 根路由错误边界
<Route path="/" element={<Layout />}
errorElement={<ErrorPage />} // 全局错误页面
>
{/* 子路由 */}
</Route>
3.4、 状态同步机制
服务器端:
javascript
<script>
window.__staticRouterHydrationData = ${JSON.stringify(context)};
</script>
客户端:
javascript
// 创建客户端路由时使用hydration数据
const router = createBrowserRouter(routes, {
hydrationData: window.__staticRouterHydrationData
});
四、最佳实践
共享路由配置:服务器和客户端使用相同的路由配置
代码分割:配合React.lazy实现按需加载
javascript
const AdminPage = React.lazy(() => import('./AdminPage'));
<Route path="/admin" element={<AdminPage />} />
数据缓存:在服务器端使用缓存策略减少API调用
流式渲染:使用renderToPipeableStream提升性能
安全考虑:正确处理用户输入,防止XSS攻击
五、与传统SSR方案对比

StaticRouterProvider
提供了现代化的SSR
解决方案,通过统一的路由配置和数据加载机制 ,简化了服务端渲染的复杂度,同时保持了与客户端路由一致的开发体验。