React项目中服务器端渲染SSR的实现与优化详解

 更新时间:2025年03月25日 09:39:23   作者:前端大白话  
在传统的 React 项目里,页面的渲染工作是在浏览器里完成的,而服务器端渲染(SSR)则是让服务器先把 React 组件渲染成 HTML 字符串,再把这个 HTML 字符串发送给浏览器,下面我们就来看看具体实现方法吧

什么是服务器端渲染(SSR)

在传统的 React 项目里,页面的渲染工作是在浏览器里完成的。也就是当你访问一个网页时,浏览器会先下载 HTML、CSS 和 JavaScript 文件,接着运行 JavaScript 代码来生成页面内容。而服务器端渲染(SSR)则是让服务器先把 React 组件渲染成 HTML 字符串,再把这个 HTML 字符串发送给浏览器。这样一来,浏览器就能直接显示已经渲染好的页面,不用再等待 JavaScript 代码运行了。

SSR 的优势

更快的初始加载速度:因为浏览器拿到的是已经渲染好的 HTML,所以能更快地显示页面内容,减少用户等待时间。

更好的 SEO:搜索引擎爬虫可以直接读取服务器返回的 HTML 内容,有利于网站在搜索引擎中的排名。

更好的用户体验:特别是在网络较慢的情况下,用户能更快地看到页面内容,提升体验。

如何在 React 项目中进行 SSR

下面我会一步步教你如何在 React 项目中实现 SSR。

1. 创建 React 项目

首先,你得创建一个新的 React 项目。可以使用 create-react-app 来创建:

npx create-react-app my-ssr-app
cd my-ssr-app

2. 安装必要的依赖

我们需要安装一些额外的依赖,像 express 用于创建服务器,react-dom/server 用于在服务器端渲染 React 组件。

npm install express react-dom

3. 修改项目结构

在项目根目录下创建一个 server.js 文件,这个文件将用于创建服务器和处理 SSR。

4. 编写 server.js 文件

下面是 server.js 文件的详细代码,每一行都有注释:

// 引入 express 模块,用于创建服务器
const express = require('express');
// 创建一个 express 应用实例
const app = express();
// 引入 React 库
const React = require('react');
// 引入 ReactDOMServer 用于在服务器端渲染 React 组件
const ReactDOMServer = require('react-dom/server');
// 引入 App 组件,这里假设你的主组件是 App
const App = require('./src/App').default;

// 处理根路径的请求
app.get('/', (req, res) => {
    // 使用 ReactDOMServer.renderToString 方法将 App 组件渲染成 HTML 字符串
    const html = ReactDOMServer.renderToString(<App />);
    // 定义一个完整的 HTML 页面模板,将渲染好的 HTML 字符串插入到模板中
    const page = `
        <!DOCTYPE html>
        <html lang="en">
        <head>
            <meta charset="UTF-8">
            <meta name="viewport" content="width=device-width, initial-scale=1.0">
            <title>My SSR App</title>
        </head>
        <body>
            <!-- 插入渲染好的 HTML 字符串 -->
            <div id="root">${html}</div>
            <!-- 引入客户端的 JavaScript 文件 -->
            <script src="/static/js/bundle.js"></script>
        </body>
        </html>
    `;
    // 将完整的 HTML 页面发送给客户端
    res.send(page);
});

// 监听 3001 端口,启动服务器
const port = 3001;
app.listen(port, () => {
    console.log(`Server is running on port ${port}`);
});

5. 修改 src/index.js 文件

在 src/index.js 文件中,我们需要使用 hydrateRoot 方法来将服务器端渲染的 HTML 与客户端的 React 代码进行关联。

// 引入 React 库
import React from 'react';
// 引入 ReactDOM 用于在客户端渲染 React 组件
import ReactDOM from 'react-dom/client';
// 引入 App 组件
import App from './App';

// 获取 id 为 root 的 DOM 元素
const rootElement = document.getElementById('root');
// 使用 hydrateRoot 方法将服务器端渲染的 HTML 与客户端的 React 代码进行关联
const root = ReactDOM.hydrateRoot(rootElement, <App />);

6. 运行项目

首先,启动服务器:

node server.js

然后,在浏览器中访问 http://localhost:3001,你就可以看到已经使用 SSR 渲染的页面了。

总结

通过以上步骤,你就可以在 React 项目中实现服务器端渲染(SSR)了。SSR 能带来更快的初始加载速度、更好的 SEO 和用户体验。希望这个教程能帮助你理解和实现 SSR。

如何优化React项目的服务器端渲染性能

在 React 项目里,优化服务器端渲染(SSR)性能可从多方面着手,下面是一些实用的优化方法和对应的代码示例。

1. 代码分割

代码分割能减少初始加载的 JavaScript 代码量,让页面更快加载。在 React 中,可使用 React.lazy 和 Suspense 来实现。

// 假设这是你的路由配置文件
import React, { lazy, Suspense } from 'react';
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';

// 懒加载组件
const Home = lazy(() => import('./pages/Home'));
const About = lazy(() => import('./pages/About'));

const App = () => {
    return (
        <Router>
            <Suspense fallback={<div>Loading...</div>}>
                <Routes>
                    <Route path="/" element={<Home />} />
                    <Route path="/about" element={<About />} />
                </Routes>
            </Suspense>
        </Router>
    );
};

​​​​​​​export default App;

上述代码借助 React.lazy 来懒加载组件,Suspense 则在组件加载期间显示加载提示。

2. 缓存机制

使用缓存可避免对相同内容的重复渲染,提升服务器性能。在 Node.js 服务器中,可使用 lru-cache 来实现简单的缓存。

const express = require('express');
const React = require('react');
const ReactDOMServer = require('react-dom/server');
const LRU = require('lru-cache');
const App = require('./src/App').default;

const app = express();
// 创建一个 LRU 缓存实例,最大缓存项数为 100
const cache = new LRU({ max: 100 });

app.get('/', (req, res) => {
    const cacheKey = req.url;
    // 检查缓存中是否存在该 URL 的渲染结果
    if (cache.has(cacheKey)) {
        const cachedHtml = cache.get(cacheKey);
        return res.send(cachedHtml);
    }

    const html = ReactDOMServer.renderToString(<App />);
    // 将渲染结果存入缓存
    cache.set(cacheKey, html);
    res.send(`
        <!DOCTYPE html>
        <html lang="en">
        <head>
            <meta charset="UTF-8">
            <meta name="viewport" content="width=device-width, initial-scale=1.0">
            <title>My SSR App</title>
        </head>
        <body>
            <div id="root">${html}</div>
            <script src="/static/js/bundle.js"></script>
        </body>
        </html>
    `);
});

const port = 3001;
app.listen(port, () => {
    console.log(`Server is running on port ${port}`);
});

此代码利用 lru-cache 来缓存渲染结果,若缓存中存在请求的 URL 对应的渲染结果,就直接返回缓存内容。

3. 异步数据获取优化

在 SSR 中,异步数据获取是性能瓶颈之一。可使用 React Query 或 SWR 等库来优化数据获取。

import React from 'react';
import { useQuery } from 'react-query';

// 模拟异步数据获取函数
const fetchData = async () => {
    const response = await fetch('https://api.example.com/data');
    return response.json();
};

const MyComponent = () => {
    // 使用 useQuery 进行数据获取
    const { data, isLoading, error } = useQuery('myData', fetchData);

    if (isLoading) return <div>Loading...</div>;
    if (error) return <div>Error: {error.message}</div>;

    return (
        <div>
            {data.map(item => (
                <div key={item.id}>{item.name}</div>
            ))}
        </div>
    );
};

export default MyComponent;

上述代码使用 React Query 的 useQuery 钩子来进行数据获取,它会自动处理缓存、重试等操作。

4. 服务器优化

合理配置服务器资源也很关键,可使用 pm2 来管理 Node.js 进程,保证服务器的高可用性和性能。

# 全局安装 pm2
npm install -g pm2
# 使用 pm2 启动服务器
pm2 start server.js

5. 优化 CSS 加载

采用 CSS-in-JS 或 extract-text-webpack-plugin 等工具,将 CSS 提取到单独的文件中,避免内联 CSS 带来的性能问题。

// 在 webpack 配置中使用 MiniCssExtractPlugin 提取 CSS
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

​​​​​​​module.exports = {
    // 其他配置...
    module: {
        rules: [
            {
                test: /\.css$/,
                use: [
                    MiniCssExtractPlugin.loader,
                    'css-loader'
                ]
            }
        ]
    },
    plugins: [
        new MiniCssExtractPlugin({
            filename: '[name].[contenthash].css'
        })
    ]
};

上述代码借助 MiniCssExtractPlugin 把 CSS 提取到单独的文件中。

通过以上这些方法,能显著优化 React 项目的服务器端渲染性能。

以上就是React项目中服务器端渲染SSR的实现与优化详解的详细内容,更多关于React服务器渲染SSR的资料请关注脚本之家其它相关文章!

相关文章

  • React深入了解原理

    React深入了解原理

    React是用于构建用户界面的JavaScript库, [1]  起源于Facebook的内部项目,该公司对市场上所有 JavaScript MVC框架都不满意,决定自行开发一套,用于架设Instagram的网站
    2022-07-07
  • React+valtio响应式状态管理

    React+valtio响应式状态管理

    Valtio是一个很轻量级的响应式状态管理库,使用外部状态代理去驱动React视图来更新,本文主要介绍了React+valtio响应式状态管理,感兴趣的可以了解一下
    2023-12-12
  • react native仿微信PopupWindow效果的实例代码

    react native仿微信PopupWindow效果的实例代码

    本篇文章主要介绍了react native仿微信PopupWindow效果的实例代码,具有一定的参考价值,有兴趣的可以了解一下
    2017-08-08
  • React SSR服务端渲染的实现示例

    React SSR服务端渲染的实现示例

    本文主要介绍了实现React服务端渲染,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2025-01-01
  • React Fiber 树思想解决业务实际场景详解

    React Fiber 树思想解决业务实际场景详解

    这篇文章主要为大家介绍了React Fiber 树思想解决业务实际场景详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-12-12
  • react组件实例属性state详解

    react组件实例属性state详解

    这篇文章主要介绍了react组件实例属性state,有状态state的组件称作复杂组件,没有状态的组件称为简单组件,状态里存储数据,数据的改变驱动页面的展示,本文结合实例代码给大家详细讲解,需要的朋友可以参考下
    2023-02-02
  • vite+react+tailwindcss的简单使用方式

    vite+react+tailwindcss的简单使用方式

    这篇文章主要介绍了vite+react+tailwindcss的简单使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-01-01
  • React Native模块之Permissions权限申请的实例相机

    React Native模块之Permissions权限申请的实例相机

    这篇文章主要介绍了React Native模块之Permissions权限申请的实例相机的相关资料,希望通过本文能帮助到大家,需要的朋友可以参考下
    2017-09-09
  • react 报错Module build failed: BrowserslistError: Unknown browser query `dead`问题的解决方法

    react 报错Module build failed: Browserslis

    这篇文章主要介绍了react 报错Module build failed: BrowserslistError: Unknown browser query `dead`问题的解决方法,需要的朋友可以参考下
    2023-06-06
  • React 中的 ForwardRef的使用示例详解

    React 中的 ForwardRef的使用示例详解

    forwardRef 相当于是为 ref 传递的一种方式,普通的函数式组件就是 Render,而 fowardRef 多加了 Ref 参数,这篇文章主要介绍了React 中的 ForwardRef的使用示例详解,需要的朋友可以参考下
    2024-06-06

最新评论