如何在React项目中实现Server-Side Rendering(SSR)以优化SEO?
React SSR 完整搭建指南(含hydrateRoot修复方案)
一、项目初始化与依赖安装
首先初始化项目并安装核心依赖:
mkdir react-ssr-demo && cd react-ssr-demo npm init -y npm install express react react-dom # 若使用ES模块,在package.json中添加 "type": "module"
二、服务端渲染核心实现
创建server.js,负责处理HTTP请求并返回服务端渲染的HTML:
import express from 'express'; import React from 'react'; import { renderToString } from 'react-dom/server'; import App from './src/App.jsx'; const app = express(); const PORT = 3000; // 托管客户端打包后的静态资源 app.use(express.static('dist')); // 处理所有路由请求 app.get('*', (req, res) => { // 将React组件渲染为HTML字符串 const appHtml = renderToString(<App />); // 构建完整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 SSR Demo</title> <meta name="description" content="服务端渲染的React应用,提升SEO"> </head> <body> <div id="root">${appHtml}</div> <!-- 引入客户端hydrate脚本 --> <script type="module" src="/client.js"></script> </body> </html> `; res.send(html); }); app.listen(PORT, () => { console.log(`Server running on http://localhost:${PORT}`); });
三、客户端hydrateRoot正确配置
创建src/client.jsx,负责将服务端渲染的静态HTML激活为可交互的React应用:
import React from 'react'; import { hydrateRoot } from 'react-dom/client'; import App from './App.jsx'; // 必须使用服务端渲染时生成的根节点 const rootElement = document.getElementById('root'); // 执行hydrate,而非render,保留服务端渲染的DOM结构 hydrateRoot(rootElement, <App />);
四、核心业务组件(src/App.jsx)
确保服务端与客户端使用同一个组件,避免DOM结构差异:
import React from 'react'; function App() { // 注意:服务端渲染时无法访问window等浏览器API,这类逻辑需放在useEffect中 React.useEffect(() => { console.log('客户端hydrate完成,应用可交互'); }, []); return ( <div> <h1>React SSR 实战示例</h1> <p>这是服务端渲染的内容,搜索引擎可直接抓取</p> <p>当前路径:{window.location.pathname}</p> </div> ); } export default App;
五、hydrateRoot未生效的常见修复方案
- DOM结构完全匹配:服务端
renderToString生成的HTML,必须和客户端hydrateRoot挂载的组件输出完全一致,不能有额外的节点、属性差异 - 静态资源路径正确:确保
express.static托管的目录是客户端打包后的输出目录(如dist),客户端脚本的src路径需对应打包后的文件名 - 避免服务端环境差异:组件中若需访问浏览器API(如
window、document),必须放在useEffect或其他客户端生命周期钩子中,服务端渲染时不会执行这些逻辑 - 打包配置正确:以Vite为例,创建
vite.config.js指定客户端打包入口:
import { defineConfig } from 'vite'; import react from '@vitejs/plugin-react'; export default defineConfig({ plugins: [react()], build: { outDir: 'dist', rollupOptions: { input: './src/client.jsx', output: { entryFileNames: 'client.js' } } } });
六、运行与验证
- 打包客户端代码:
npx vite build - 启动服务端:
node server.js - 访问
http://localhost:3000,查看页面源代码,确认<div id="root">内已有渲染好的内容(而非空节点),说明服务端渲染生效;打开控制台无hydrate相关报错,说明hydrateRoot正常工作
内容的提问来源于stack exchange,提问作者deepak kumar
相关产品推荐
相关产品推荐

