React項(xiàng)目中服務(wù)器端渲染SSR的實(shí)現(xiàn)與優(yōu)化詳解
什么是服務(wù)器端渲染(SSR)
在傳統(tǒng)的 React 項(xiàng)目里,頁(yè)面的渲染工作是在瀏覽器里完成的。也就是當(dāng)你訪問(wèn)一個(gè)網(wǎng)頁(yè)時(shí),瀏覽器會(huì)先下載 HTML、CSS 和 JavaScript 文件,接著運(yùn)行 JavaScript 代碼來(lái)生成頁(yè)面內(nèi)容。而服務(wù)器端渲染(SSR)則是讓服務(wù)器先把 React 組件渲染成 HTML 字符串,再把這個(gè) HTML 字符串發(fā)送給瀏覽器。這樣一來(lái),瀏覽器就能直接顯示已經(jīng)渲染好的頁(yè)面,不用再等待 JavaScript 代碼運(yùn)行了。
SSR 的優(yōu)勢(shì)
更快的初始加載速度:因?yàn)闉g覽器拿到的是已經(jīng)渲染好的 HTML,所以能更快地顯示頁(yè)面內(nèi)容,減少用戶等待時(shí)間。
更好的 SEO:搜索引擎爬蟲可以直接讀取服務(wù)器返回的 HTML 內(nèi)容,有利于網(wǎng)站在搜索引擎中的排名。
更好的用戶體驗(yàn):特別是在網(wǎng)絡(luò)較慢的情況下,用戶能更快地看到頁(yè)面內(nèi)容,提升體驗(yàn)。
如何在 React 項(xiàng)目中進(jìn)行 SSR
下面我會(huì)一步步教你如何在 React 項(xiàng)目中實(shí)現(xiàn) SSR。
1. 創(chuàng)建 React 項(xiàng)目
首先,你得創(chuàng)建一個(gè)新的 React 項(xiàng)目??梢允褂?create-react-app 來(lái)創(chuàng)建:
npx create-react-app my-ssr-app cd my-ssr-app
2. 安裝必要的依賴
我們需要安裝一些額外的依賴,像 express 用于創(chuàng)建服務(wù)器,react-dom/server 用于在服務(wù)器端渲染 React 組件。
npm install express react-dom
3. 修改項(xiàng)目結(jié)構(gòu)
在項(xiàng)目根目錄下創(chuàng)建一個(gè) server.js 文件,這個(gè)文件將用于創(chuàng)建服務(wù)器和處理 SSR。
4. 編寫 server.js 文件
下面是 server.js 文件的詳細(xì)代碼,每一行都有注釋:
// 引入 express 模塊,用于創(chuàng)建服務(wù)器
const express = require('express');
// 創(chuàng)建一個(gè) express 應(yīng)用實(shí)例
const app = express();
// 引入 React 庫(kù)
const React = require('react');
// 引入 ReactDOMServer 用于在服務(wù)器端渲染 React 組件
const ReactDOMServer = require('react-dom/server');
// 引入 App 組件,這里假設(shè)你的主組件是 App
const App = require('./src/App').default;
// 處理根路徑的請(qǐng)求
app.get('/', (req, res) => {
// 使用 ReactDOMServer.renderToString 方法將 App 組件渲染成 HTML 字符串
const html = ReactDOMServer.renderToString(<App />);
// 定義一個(gè)完整的 HTML 頁(yè)面模板,將渲染好的 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 頁(yè)面發(fā)送給客戶端
res.send(page);
});
// 監(jiān)聽(tīng) 3001 端口,啟動(dòng)服務(wù)器
const port = 3001;
app.listen(port, () => {
console.log(`Server is running on port ${port}`);
});5. 修改 src/index.js 文件
在 src/index.js 文件中,我們需要使用 hydrateRoot 方法來(lái)將服務(wù)器端渲染的 HTML 與客戶端的 React 代碼進(jìn)行關(guān)聯(lián)。
// 引入 React 庫(kù)
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 方法將服務(wù)器端渲染的 HTML 與客戶端的 React 代碼進(jìn)行關(guān)聯(lián)
const root = ReactDOM.hydrateRoot(rootElement, <App />);6. 運(yùn)行項(xiàng)目
首先,啟動(dòng)服務(wù)器:
node server.js
然后,在瀏覽器中訪問(wèn) http://localhost:3001,你就可以看到已經(jīng)使用 SSR 渲染的頁(yè)面了。
總結(jié)
通過(guò)以上步驟,你就可以在 React 項(xiàng)目中實(shí)現(xiàn)服務(wù)器端渲染(SSR)了。SSR 能帶來(lái)更快的初始加載速度、更好的 SEO 和用戶體驗(yàn)。希望這個(gè)教程能幫助你理解和實(shí)現(xiàn) SSR。
如何優(yōu)化React項(xiàng)目的服務(wù)器端渲染性能
在 React 項(xiàng)目里,優(yōu)化服務(wù)器端渲染(SSR)性能可從多方面著手,下面是一些實(shí)用的優(yōu)化方法和對(duì)應(yīng)的代碼示例。
1. 代碼分割
代碼分割能減少初始加載的 JavaScript 代碼量,讓頁(yè)面更快加載。在 React 中,可使用 React.lazy 和 Suspense 來(lái)實(shí)現(xiàn)。
// 假設(shè)這是你的路由配置文件
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 來(lái)懶加載組件,Suspense 則在組件加載期間顯示加載提示。
2. 緩存機(jī)制
使用緩存可避免對(duì)相同內(nèi)容的重復(fù)渲染,提升服務(wù)器性能。在 Node.js 服務(wù)器中,可使用 lru-cache 來(lái)實(shí)現(xiàn)簡(jiǎn)單的緩存。
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();
// 創(chuàng)建一個(gè) LRU 緩存實(shí)例,最大緩存項(xiàng)數(shù)為 100
const cache = new LRU({ max: 100 });
app.get('/', (req, res) => {
const cacheKey = req.url;
// 檢查緩存中是否存在該 URL 的渲染結(jié)果
if (cache.has(cacheKey)) {
const cachedHtml = cache.get(cacheKey);
return res.send(cachedHtml);
}
const html = ReactDOMServer.renderToString(<App />);
// 將渲染結(jié)果存入緩存
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 來(lái)緩存渲染結(jié)果,若緩存中存在請(qǐng)求的 URL 對(duì)應(yīng)的渲染結(jié)果,就直接返回緩存內(nèi)容。
3. 異步數(shù)據(jù)獲取優(yōu)化
在 SSR 中,異步數(shù)據(jù)獲取是性能瓶頸之一。可使用 React Query 或 SWR 等庫(kù)來(lái)優(yōu)化數(shù)據(jù)獲取。
import React from 'react';
import { useQuery } from 'react-query';
// 模擬異步數(shù)據(jù)獲取函數(shù)
const fetchData = async () => {
const response = await fetch('https://api.example.com/data');
return response.json();
};
const MyComponent = () => {
// 使用 useQuery 進(jìn)行數(shù)據(jù)獲取
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 鉤子來(lái)進(jìn)行數(shù)據(jù)獲取,它會(huì)自動(dòng)處理緩存、重試等操作。
4. 服務(wù)器優(yōu)化
合理配置服務(wù)器資源也很關(guān)鍵,可使用 pm2 來(lái)管理 Node.js 進(jìn)程,保證服務(wù)器的高可用性和性能。
# 全局安裝 pm2 npm install -g pm2 # 使用 pm2 啟動(dòng)服務(wù)器 pm2 start server.js
5. 優(yōu)化 CSS 加載
采用 CSS-in-JS 或 extract-text-webpack-plugin 等工具,將 CSS 提取到單獨(dú)的文件中,避免內(nèi)聯(lián) CSS 帶來(lái)的性能問(wèn)題。
// 在 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 提取到單獨(dú)的文件中。
通過(guò)以上這些方法,能顯著優(yōu)化 React 項(xiàng)目的服務(wù)器端渲染性能。
以上就是React項(xiàng)目中服務(wù)器端渲染SSR的實(shí)現(xiàn)與優(yōu)化詳解的詳細(xì)內(nèi)容,更多關(guān)于React服務(wù)器渲染SSR的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
React+valtio響應(yīng)式狀態(tài)管理
Valtio是一個(gè)很輕量級(jí)的響應(yīng)式狀態(tài)管理庫(kù),使用外部狀態(tài)代理去驅(qū)動(dòng)React視圖來(lái)更新,本文主要介紹了React+valtio響應(yīng)式狀態(tài)管理,感興趣的可以了解一下2023-12-12
react native仿微信PopupWindow效果的實(shí)例代碼
本篇文章主要介紹了react native仿微信PopupWindow效果的實(shí)例代碼,具有一定的參考價(jià)值,有興趣的可以了解一下2017-08-08
React SSR服務(wù)端渲染的實(shí)現(xiàn)示例
本文主要介紹了實(shí)現(xiàn)React服務(wù)端渲染,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2025-01-01
React?Fiber?樹思想解決業(yè)務(wù)實(shí)際場(chǎng)景詳解
這篇文章主要為大家介紹了React?Fiber?樹思想解決業(yè)務(wù)實(shí)際場(chǎng)景詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12
vite+react+tailwindcss的簡(jiǎn)單使用方式
這篇文章主要介紹了vite+react+tailwindcss的簡(jiǎn)單使用方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-01-01
React Native模塊之Permissions權(quán)限申請(qǐng)的實(shí)例相機(jī)
這篇文章主要介紹了React Native模塊之Permissions權(quán)限申請(qǐng)的實(shí)例相機(jī)的相關(guān)資料,希望通過(guò)本文能幫助到大家,需要的朋友可以參考下2017-09-09
react 報(bào)錯(cuò)Module build failed: Browserslis
這篇文章主要介紹了react 報(bào)錯(cuò)Module build failed: BrowserslistError: Unknown browser query `dead`問(wèn)題的解決方法,需要的朋友可以參考下2023-06-06

