新闻中心
解决React SSR中Hydration警告:EJS模板注入的细微之处

理解React Hydration警告
在react服务器端渲染(ssr)应用中,当服务器生成html并发送到客户端后,客户端的react会尝试“接管”这份html,将其转化为可交互的组件树,这个过程称为hydration(水合)。如果客户端react在hydration过程中发现服务器端渲染的html结构与它期望的结构不匹配,就会抛出类似“expected server html to contain a matching 这种警告通常不是因为HTML本身语法错误,而是因为客户端和服务器端渲染的HTML在细节上存在差异,例如多余的空白字符、注释或属性顺序等。React对这种匹配要求非常严格。 在不使用Next.js等框架,而是采用Express、EJS和React构建SSR应用时,开发者通常会遇到上述问题。以下是一个典型的设置: Express服务器接收请求后,使用renderToString将React组件渲染成HTML字符串,然后将该字符串注入到EJS模板中。 一个包含HTML语义元素的React组件。 这是将React组件HTML注入到完整HTML骨架的地方。 在上述EJS模板中,开发者可能会习惯性地将注释和放在新行,这正是导致Hydration警告的常见原因。 Hydration警告的根本原因在于EJS模板中注入React组件时,父容器div.root与实际注入的reactComponent之间存在了多余的空白字符或换行符。当服务器端渲染时,renderToString会生成不包含这些额外空白的HTML字符串。然而,当EJS模板将这个字符串插入到 而客户端的React在Hydration时,期望的是一个紧凑的结构,例如: 这种服务器端和客户端期望的HTML结构差异(即使只是空白字符的差异),都会被React的Hydration机制检测为不匹配,从而触发警告并回退到客户端渲染。 青泥学术AI写作辅助平台 解决此问题的关键在于确保EJS模板中React组件的注入是完全内联的,不引入任何额外的空白字符或换行符。 将EJS模板中的注入点修改为以下形式: 通过将直接紧跟在 虽然不是导致Hydration警告的直接原因,但将根容器的class="root"改为id="root"是React官方推荐的做法。客户端React通常通过ReactDOM.hydrateRoot(document.getElementById('root'), )或ReactDOM.render(, document.getElementById('root'))来挂载或水合应用,使用id选择器能够更清晰、更高效地定位根元素。 同时,客户端的入口文件也需要相应调整: 通过上述方法,特别是确保EJS模板中React组件的内联注入,可常见的SSR设置与问题场景
1. 服务器端渲染逻辑 (server.jsx)
// server.jsx (简化示例)
const express = require('express');
const path = require('path');
const React = require('react');
const ReactDOMServer = require('react-dom/server');
const ejs = require('ejs');
const SchoolPage = require('./dist/SchoolPage').default; // 确保路径正确
const app = express();
app.use(express.static(path.join(__dirname, 'dist'))); // 假设静态文件在dist
app.get("/campus/:id/locations", async (req, res) => {
const reactComponentHtml = ReactDOMServer.renderToString(<SchoolPage />);
const filePath = path.join(__dirname, "dist", "school-page.ejs");
ejs.renderFile(filePath, { reactComponent: reactComponentHtml }, (err, html) => {
if (err) {
console.error("Error rendering template:", err);
return res.status(500).end();
}
res.send(html);
});
});
app.listen(3000, () => console.log('Server running on port 3000'));2. React根组件 (SchoolPage.jsx)
// SchoolPage.jsx
import React from 'react';
import MiniSearchBar from './MiniSearchBar'; // 假设有这个组件
import ContentContainer from './ContentContainer'; // 假设有这个组件
export default function SchoolPage() {
return (
<>
<header>
<picture title="Campus Eats">
<source
media="(min-width: 400px)"
srcSet="/images/campus-eats-logo-black.svg"
/>
@@##@@
</picture>
<n* className="places-at">
<h2>Places</h2>
<h2>at</h2>
<div className="search-container">
<MiniSearchBar></MiniSearchBar>
</div>
</n*>
<n* className="login-signup">
<button className="login">Log in</button>
<button className="signup">Sign up</button>
</n*>
</header>
<section>
<ContentContainer></ContentContainer>
</section>
</>
);
}3. EJS模板 (school-page.ejs)
<!-- school-page.ejs (存在问题的写法) -->
<!DOCTYPE html>
<html lang="en">
<head>
<!-- ... 省略head内容 ... -->
<title>Document</title>
</head>
<body>
<div class="root">
<!-- Rendered React component will be injected here -->
<%- reactComponent %>
</div>
<script src="/school-page.js" defer></script>
</body>
</html>问题根源:EJS模板中的隐形陷阱
<div class="root">
<!-- Rendered React component will be injected here -->
<header>...</header>
<section>...</section>
</div>
<div class="root"><header>...</header><section>...</section></div>
青泥AI
360
查看详情
解决方案
1. 关键修复:内联注入React组件
<!-- school-page.ejs (修复后的写法) -->
<!DOCTYPE html>
<html lang="en">
<head>
<!-- ... 省略head内容 ... -->
<title>Document</title>
</head>
<body>
<div class="root"><%- reactComponent %></div>
<script src="/school-page.js" defer></script>
</body>
</html>2. 最佳实践:使用ID选择器
<!-- school-page.ejs (更佳实践) -->
<!DOCTYPE html>
<html lang="en">
<head>
<!-- ... 省略head内容 ... -->
<title>Document</title>
</head>
<body>
<div id="root"><%- reactComponent %></div>
<script src="/school-page.js" defer></script>
</body>
</html>// client-side.js (或 school-page.js)
import React from 'react';
import { hydrateRoot } from 'react-dom/client'; // React 18+
import SchoolPage from './SchoolPage';
// React 18+
hydrateRoot(document.getElementById('root'), <SchoolPage />);
// 或者 React 17及以下
// import ReactDOM from 'react-dom';
// ReactDOM.hydrate(<SchoolPage />, document.getElementById('root'));注意事项与总结
以有效解决React SSR中的Hydration警告,确保应用能够充分利用服务器端渲染的优势,提供更好的用户体验和SEO表现。
以上就是解决React SSR中Hydration警告:EJS模板注入的细微之处的详细内容,更多请关注其它相关文章!
# 当地的网站建设视频
# 换行符
# 自定义
# 退到
# 服务端
# 如何实现
# 的是
# 电子商务基础网站建设
# 岳麓区网站建设
# 之处
# 营销推广策略制定
# 织梦首页标题seo
# 黑龙江平台推广营销方案
# 香港企业网站优化
# 成都易优seo博客
# 花店营销宣传推广咨询
# 黄石短视频营销推广公司
# react
# 选择器
# 不匹配
# 客户端
# red
# id选择器
# 组件渲染
# ai
# 工具
# app
# 浏览器
# seo
# svg
# go
# js
# html
相关栏目:
【
科技资讯46185 】
【
网络学院92790 】
相关推荐:
优化 Jest 模拟:强制未实现函数抛出错误以提升测试效率
2026年发布! 美少女养成动作RPG《神剑少女战记》发布实机演示
深入理解J*aScript Promise异步执行与微任务队列
Surface怎么安装系统 微软Surface Pro U盘重装win11教程
Django表单验证失败时保留用户输入数据的最佳实践
地铁跑酷免费秒玩入口链接 地铁跑酷小游戏免费秒玩网站
qq游戏手机版下载安装_qq游戏移动端入口
如何将HTML表格多行数据保存到Google Sheet
PHP中高效并行检查多链接状态的教程
qq游戏免费畅玩入口_qq游戏电脑版快速启动
React Router 嵌套组件中 URL 重定向问题的解决方案
双系统安装时,如何设置默认启动系统? msconfig命令了解一下!
J*aScript中管理异步API调用:确保操作顺序与数据一致性
R星幕后开发视频泄露 包含《GTA6》等多款大作
12306选座怎么选到特殊座位_12306特殊座位选择注意事项
微信网页版官方入口教程 微信网页版网页版快速登录步骤
微博网页版官方账号登录 微博网页版内容浏览使用指南
Node.js CSV 数据处理:基于字段值条件过滤整条记录的策略
yy漫画网页版官方入口_yy漫画官网登录页面链接
Sublime怎么配置Nim语言环境_Sublime Nim代码高亮与补全
Safari怎么安装扩展程序 浏览器插件安装与管理方法【详解】
正确连接J*aScript到HTML实现可点击图片与自定义事件处理
Golang指针如何与map组合使用_Golang map指针组合实践
如何创建没有密码的Windows本地账户_跳过微软账户登录的技巧【教程】
微信网页版官方入口直达 微信网页版网页版登录使用方法
Win10如何清理注册表垃圾 Win10注册表维护与优化指南【慎用】
Mac怎么锁定备忘录_Mac备忘录加密设置教程
win11 arm版怎么安装 M1/M2 Mac虚拟机安装ARM win11的方法
网易大神怎么保存别人动态的图片_网易大神动态图片保存方法
Django通过AJAX异步上传图片并保存至模型的完整指南
汽水音乐车机版8.9下载 汽水音乐车机版8.9版本安装入口
汽水音乐在线版入口_汽水音乐网页播放手册
必由学官方登录入口 必由学教师学生账号快速访问
Sublime Text怎么显示空格和制表符_Sublime显示不可见字符设置
Golang如何实现Web文件静态资源服务器_Golang静态资源服务器开发与实践
俄罗斯Yandex免登录入口_Yandex搜索引擎官网一键直达
Win11蓝牙耳机断连怎么解决 Win11蓝牙设置重新配对与驱动更新【技巧】
PostgreSQL海量数据高效导入策略:Python与Django实践指南
在J*a项目里如何构建对象之间的契约_接口约束的实际落地
J*a应用程序首次运行自动创建文件与目录的最佳实践
在WordPress中通过REST API获取BasicAuth保护的远程文章
利用Bokeh CustomJS动态控制DataTable列可见性
Typer应用中动态命令行参数的解析与处理
小红书网页版入口链接分享 小红书官网直接进
一加Ace 6T支持全新明眸护眼:通过了最严苛的护眼小金标认证
LINUX的perf命令入门_LINUX官方性能分析工具的使用与解读
抖音小游戏合成大西瓜免费秒玩入口链接 抖音小游戏热门合集秒玩网站
Win11怎么设置鼠标主按键_Win11鼠标左右键功能互换
谷歌google账号怎么注册账号 谷歌账号注册官方流程
J*aScript中localStorage数据的获取、清洗与格式化教程


2025-10-10
浏览次数:次
返回列表