客户端组件通过 hydration“接上”服务端渲染的 HTML,需确保 DOM 结构、初始状态(如 window.__INITIAL_STATE__)和生命周期严格对齐,否则事件丢失、状态失效且无报错。

服务端渲染后,客户端组件怎么“接上”?
服务端吐出的 HTML 不是终点,而是 hydration 的起点。如果没对齐,React/Vue 会静默放弃绑定事件、丢焦点、失状态——你点按钮没反应,不是 JS 报错,是 hydration 失败了。
-
renderToString(React)或renderToString(Vue SSR)必须在 Node 环境调用,它不执行useEffect、不访问window,只生成纯 HTML 字符串 - 服务端生成的 HTML 必须包裹
window.__INITIAL_STATE__,且 DOM 结构要和客户端首次 mount 完全一致:比如服务端是<div id="root"><p>hi</p></div>,客户端就不能多一层<section>或少一个闭合标签 - 不要用
res.send('<html><body>...</body></html>')直接发整页——浏览器插入时会破坏已有 layout,导致 hydration 树不匹配 - 正确做法:服务端只返回 fragment 字符串(如
<div id="root">${ssrHtml}</div>),由 EJS/Nunjucks 模板注入到预设的layout.ejs中
EJS 里怎么传数据给 React 组件?
模板引擎和前端框架之间没有自动桥接,所有 props 必须显式注入,否则客户端组件拿到的是空对象或 undefined。
- 用
res.render('index', { data: { user: { name: 'Alice' } }, initialState: { theme: 'dark' } })把初始数据传进 EJS - 在
index.ejs中,用<script>window.__INITIAL_STATE__ = <%= JSON.stringify(initialState) %></script>注入全局变量(注意用<%=而非<%-,避免转义破坏 JSON 结构) - 组件内通过
const state = window.__INITIAL_STATE__ || {}读取,不能直接依赖 props 默认值,因为 SSR 时 props 是空的 - 如果字段可能为
null或undefined,判断要用data?.user?.name !== undefined,而不是if (data.user.name)——后者在 name 是空字符串时也失败
为什么 v-html 里的按钮点不了?
这是常见误解:v-html 只插入静态 HTML,Vue 不会编译其中的指令,@click、v-model 全部失效。
重要:对 React 或 Next.js 代码的任何更改必须先阅读本技能。Vercel 工程团队的 React 与 Next.js 指南,涵盖可视化...
- 错误写法:
<div v-html="getHtml()"></div>,其中getHtml()返回'<button @click="handle()">Click</button>' - 正确解法:改用
render function或h()创建可响应的 VNode,例如:h('button', { onClick: () => this.handleClick() }, 'Click') - 如果必须动态生成结构,优先用
<component :is="dynamicComp" :props="data"/>,而不是拼 HTML 字符串 - 第三方富文本内容(如用户提交的 HTML)只能用
v-html,但交互逻辑得靠事件委托 +dataset提取上下文,不能指望 Vue 自动绑定
dialog、<template> 这类原生标签在 SSR 里怎么处理?
它们本身不参与服务端渲染流程,但若出现在 SSR 输出中,又没做对应初始化,hydration 就会断裂。
立即学习“前端免费学习笔记(深入)”;
-
<dialog>默认display: none,SSR 吐出来只是个空壳;客户端必须调用dialog.showModal()才可见——不能靠 CSSdisplay: block强行激活 - 用
<template>插入服务端未生成的片段(比如 fetch 后插入 HTML),这部分 DOM 不会被 hydrate,事件监听器不会自动挂载,ref也不会被识别 - 解决方案:把需要交互的区域全部纳入 SSR 范围,或明确标记 hydration boundary(如 React 的
createRoot分段挂载) - Firefox 不支持
::backdrop,如果模态框用了该伪元素做遮罩,得额外加一层<div class="overlay"></div>并手动控制显隐
window.__INITIAL_STATE__ 注入,或一次 h() 替代 v-html。


















