You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ReactJS组件渲染:服务端与客户端执行步骤及核心原理咨询

React服务端渲染(SSR)核心流程与组件渲染全解析

作为React新手,刚入门时对SSR(服务端渲染)和前后端渲染分工感到困惑完全正常——我当初也花了不少时间捋清楚这些细节!下面我会一步步拆解你的问题:

一、服务端渲染时的后台流程:render代码是否在服务端执行?

是的,在SSR模式下,React的render相关代码(比如renderToString、renderToPipeableStream)是在服务端执行的,具体流程是:

  • 当用户请求某个页面时,服务端首先会获取该页面所需的所有数据(比如从数据库/API拉取文章、用户信息)
  • 接着服务端会创建React组件树,并把获取到的数据作为props传入组件
  • 调用React提供的服务端渲染API(比如renderToString),将组件树转换为完整的HTML字符串
  • 最后把这个HTML字符串嵌入到一个基础HTML模板里(模板中会包含React客户端脚本的引用),返回给浏览器

举个简化的服务端代码示例:

import React from 'react';
import { renderToString } from 'react-dom/server';
import App from './App';

// 服务端路由处理函数
async function handleRequest(req, res) {
  // 1. 获取页面数据
  const pageData = await fetchPageData(req.path);
  // 2. 渲染组件为HTML字符串
  const appHtml = renderToString(<App data={pageData} />);
  // 3. 嵌入模板并返回
  const html = `
    <!DOCTYPE html>
    <html>
      <head><title>React SSR</title></head>
      <body>
        <div id="root">${appHtml}</div>
        <script src="/client-bundle.js"></script>
      </body>
    </html>
  `;
  res.send(html);
}

二、客户端是否会将Virtual DOM与浏览器DOM合并?

准确来说,这个过程叫做hydrate(注水),而不是“合并”:

  • 浏览器接收到服务端返回的HTML后,会先解析并渲染出真实的DOM节点,用户此时已经能看到静态的页面内容
  • 当客户端的React脚本加载完成后,会创建对应的Virtual DOM树,然后和浏览器中已有的真实DOM进行对比
  • React会复用已有的真实DOM节点,只给它们绑定事件监听器、激活交互功能,而不是重新渲染整个DOM树

需要注意:如果服务端生成的HTML和客户端Virtual DOM对应的结构不匹配,React会抛出警告,严重时可能会重新渲染部分DOM——所以要确保前后端使用的组件代码和数据是一致的。

客户端hydrate的代码示例:

import React from 'react';
import { hydrateRoot } from 'react-dom/client';
import App from './App';

// 复用服务端生成的DOM节点,进行注水
const root = document.getElementById('root');
hydrateRoot(root, <App data={window.__INITIAL_DATA__} />);

(这里window.__INITIAL_DATA__是服务端嵌入到HTML中的初始数据,保证客户端和服务端的组件props一致)

三、如何处理浏览器兼容性问题?

React的兼容性主要从三个层面来处理:

1. React本身的版本兼容

  • React 17及之前的版本支持IE11,但需要额外配置polyfills;React 18已经放弃了对IE的支持
  • 如果需要兼容旧浏览器,建议使用React 17,并配合Babel和polyfill工具

2. 服务端渲染的HTML兼容性

服务端生成的是标准的HTML,只要浏览器支持基本的HTML5语法(绝大多数现代浏览器和IE9+都支持),就能正常显示静态内容,这部分几乎不需要额外处理。

3. 客户端JS的兼容性

  • 语法转译:用Babel把ES6+的语法转译为ES5,确保旧浏览器能识别。比如通过@babel/preset-env配置目标浏览器
  • API补全(Polyfill):对于旧浏览器不支持的新JS API(比如Promise、Array.prototype.includes),用core-js等工具注入polyfill。可以在项目入口文件中引入,或者通过Babel按需自动注入
  • 避免服务端执行浏览器特有API:比如window、document这些对象在服务端不存在,如果在组件的render或useMemo等服务端会执行的生命周期中调用,会报错。正确的做法是把这些代码放在useEffect(客户端才会执行)里,或者用条件判断:
    useEffect(() => {
      // 这里的代码只会在客户端执行,可以安全使用window/document
      console.log(window.innerWidth);
    }, []);
    

四、服务端与客户端组件渲染的具体步骤

服务端渲染步骤

  1. 接收请求:用户通过浏览器发送HTTP请求到服务端
  2. 数据预取:服务端根据请求路径,获取该页面所需的所有数据(比如调用API、查询数据库)
  3. 创建组件树:使用预取到的数据作为props,创建React组件实例
  4. 生成HTML字符串:调用服务端渲染API(如renderToString)将组件树转换为HTML字符串
  5. 返回响应:把HTML字符串嵌入到基础模板中,添加客户端脚本引用,返回给浏览器

客户端Hydrate步骤

  1. 解析HTML:浏览器接收HTML响应,解析并渲染出真实的DOM,用户看到静态页面
  2. 加载客户端脚本:浏览器下载并执行React客户端bundle文件
  3. 初始化Virtual DOM:根据服务端传入的初始数据,创建对应的Virtual DOM树
  4. Hydrate绑定:将Virtual DOM与已有的真实DOM进行对比,复用DOM节点并绑定事件监听器
  5. 激活交互:组件进入正常的客户端生命周期,支持用户交互、状态更新等后续操作

如果是纯CSR(客户端渲染)模式,服务端只会返回一个空的HTML壳子,所有渲染工作都在客户端完成,但你问的是服务端流程,所以重点在SSR。

内容的提问来源于stack exchange,提问作者Rad'Val

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 07:10:18