什么是服务器端渲染?如何用React做到这一点?
服务器端渲染, 也被称为固态继电器,是JavaScript应用程序在服务器而不是在浏览器中呈现的功能。
我们为什么要这样做?
- 它使您的网站拥有更快的首页加载时间,这是获得良好用户体验的关键
- 这对于SEO至关重要:搜索引擎无法(还?)高效,正确地索引专门呈现客户端的应用程序。尽管Google对索引编制有了最新的改进,但还有其他搜索引擎,无论如何Google都不是完美的。另外,Google偏爱加载时间短的网站,并且必须加载客户端不利于提高速度
- 人们在社交媒体上共享您的网站页面时非常好,因为他们可以轻松收集很好地共享链接所需的元数据(图像,标题,描述..)
如果没有服务器端渲染,您的所有服务器都将是一个没有正文的HTML页面,只有一些脚本标记,然后浏览器就会使用这些脚本标记来呈现应用程序。
客户端渲染的应用程序非常适合在加载第一页后进行的任何后续用户交互。服务器端渲染使我们可以在客户端渲染的应用程序和后端渲染的应用程序的中间位置获得优势:页面是在服务器端生成的,但是与页面加载后的所有交互都是在客户端处理的。
但是,服务器端渲染也有其缺点:
- 可以说,简单的SSR概念证明很简单,但是SSR的复杂性会随着应用程序的复杂性而增加
- 在服务器端渲染大型应用程序可能会占用大量资源,并且在繁重的负载下,与客户端渲染相比,它甚至可能提供较慢的体验,因为您只有一个瓶颈
服务器端渲染React应用所需的一个非常简单的示例
SSR设置可能会变得非常非常复杂,并且大多数教程都将引入Redux,反应路由器以及从一开始的许多其他概念。
为了了解SSR的工作原理,让我们从基础知识开始实施概念验证。
如果您只想研究提供SSR的库,而不必打扰基础工作,请跳过本段
为了实现基本的SSR,我们将使用Express。
如果您不熟悉Express,或者需要一些帮助,请在这里查看我的免费Express Handbook:https://flaviocopes.com/page/ebooks/。
警告:SSR的复杂性会随着应用程序的复杂性而增加。这是渲染基本React应用程序的最低要求。对于更复杂的需求,您可能需要做更多的工作,或者还检查React的SSR库。
我假设你用以下方法启动了一个React应用create-react-app
。如果您只是尝试,请立即使用安装npx create-react-app ssr
。
使用终端转到主应用程序文件夹,然后运行:
npm install express
您的应用程序目录中有一组文件夹。创建一个名为的新文件夹server
,然后进入它并创建一个名为server.js
。
继create-react-app
约定,该应用程序位于src/App.js
文件。我们将加载该组件,并使用ReactDOMServer.renderToString(),由提供react-dom
。
您得到的内容./build/index.html
文件,然后替换<div id="root"></div>
占位符,它是应用程序默认挂接的标签,带有`<div id="root">\${ReactDOMServer.renderToString(<App />)}</div>
。
里面的所有内容build
Express将按原样提供该文件夹。
import path from 'path'
import fs from 'fs'
import express from ‘express’
import React from ‘react’
import ReactDOMServer from ‘react-dom/server’
import App from ‘…/src/App’
const PORT = 8080
const app = express()
const router = express.Router()
const serverRenderer = (req, res, next) => {
fs.readFile(path.resolve(’./build/index.html’), ‘utf8’, (err, data) => {
if (err) {
console.error(err)
return res.status(500).send(‘An error occurred’)
}
return res.send(
data.replace(
‘<div id=“root”></div>’,
<div id="root"></span><span style="color:#e6db74">${</span><span style="color:#a6e22e">ReactDOMServer</span>.<span style="color:#a6e22e">renderToString</span>(<span style="color:#f92672"><</span><span style="color:#a6e22e">App</span> <span style="color:#f92672">/></span>)<span style="color:#e6db74">}</span><span style="color:#e6db74"></div>
)
)
})
}
router.use(’^/$’, serverRenderer)
router.use(
express.static(path.resolve(__dirname, ‘…’, ‘build’), { maxAge: ‘30d’ })
)
// tell the app to use the above rules
app.use(router)
// app.use(express.static(’./build’))
app.listen(PORT, () => {
console.log(SSR running on port </span><span style="color:#e6db74">${</span><span style="color:#a6e22e">PORT</span><span style="color:#e6db74">}</span><span style="color:#e6db74">
)
})
现在,在客户端应用程序中src/index.js
,而不是致电ReactDOM.render()
:
ReactDOM.render(<App />, document.getElementById('root'))
称呼ReactDOM.hydrate()
相同,但是一旦React加载,它还具有将事件侦听器附加到现有标记的附加功能:
ReactDOM.hydrate(<App />, document.getElementById('root'))
所有的Node.js代码都需要由巴别塔,因为服务器端Node.js代码不了解JSX,也不了解ES模块(我们用于include
声明)。
安装以下4个软件包:
npm install @babel/register @babel/preset-env @babel/preset-react ignore-styles
ignore-styles
是Babel实用程序,它将告诉它忽略使用import
句法。
让我们在中创建一个入口点server/index.js
:
require('ignore-styles')
require(’@babel/register’)({
ignore: [/(node_modules)/],
presets: [’@babel/preset-env’, ‘@babel/preset-react’]
})
require(’./server’)
编译React应用程序,以填充build /文件夹:
npm run build
让我们运行这个:
node server/index.js
我说这是一种简单的方法,它是:
- 使用导入时,它无法正确处理渲染图像,而导入需要Webpack才能正常工作(这使整个过程变得非常复杂)
- 它不处理页面标题元数据,这对于SEO和社交共享目的非常重要(除其他事项外)
因此,虽然这是使用的一个很好的例子ReactDOMServer.renderToString()
和ReactDOM.hydrate
要获得此基本的服务器端呈现效果,对于实际使用而言还不够。
使用库的服务器端渲染
SSR很难做到正确,而且React没有实际的方法来实现它。
如果值得付出麻烦,复杂化和开销来获得好处,而不是使用其他技术来提供这些页面,那还是值得商de的。关于Reddit的讨论在这方面有很多意见。
当服务器端渲染很重要时,我的建议是依赖从一开始就牢记此目标的预制库和工具。
免费下载我的反应手册
更多反应教程:
- 一个React简单的应用示例:通过API获取GitHub用户信息
- 用React构建一个简单的计数器
- 用于React开发的VS代码设置
- 如何通过React Router将道具传递给子组件
- 使用Electron和React创建一个应用
- 教程:使用React创建电子表格
- 学习React的路线图
- 了解如何使用Redux
- JSX入门
- 样式化的组件
- Redux Saga简介
- React Router简介
- React简介
- 反应组件
- 虚拟DOM
- 反应事件
- 反应状态
- 反应道具
- 反应片段
- React Context API
- 反应PropTypes
- 反应概念:声明式
- React:如何在点击时显示其他组件
- 如何在React JSX内部循环
- 道具与状态在React中
- 您应该使用jQuery还是React?
- 使用React需要知道多少JavaScript?
- 盖茨比介绍
- 如何在React中引用DOM元素
- React中的单向数据流
- 反应高阶组件
- 反应生命周期事件
- 反应概念:不变性
- 反应概念:纯度
- React钩子简介
- create-react-app简介
- 反应概念:组成
- React:演示组件与容器组件
- React中的代码拆分
- 使用React进行服务器端渲染
- 如何安装React
- React中的CSS
- 在React中使用SASS
- 在React中处理表单
- 反应严格模式
- 反应门户
- 反应渲染道具
- 测试React组件
- 如何在React中将参数传递给事件处理程序
- 如何处理React中的错误
- 如何在JSX中返回多个元素
- React中的条件渲染
- 反应,如何将道具转移到子组件
- 如何在React中获取输入元素的值
- 如何使用useState React钩子
- 如何使用useCallback React钩子
- 如何使用useEffect React钩子
- 如何使用useMemo React钩子
- 如何使用useRef React钩子
- 如何使用useContext React钩子
- 如何使用useReducer React钩子
- 如何将您的React应用程序连接到相同来源的后端
- 到达路由器教程
- 如何使用React Developer Tools
- 如何学习React
- 如何调试React应用程序
- 如何在React中呈现HTML
- 如何修复`dangerouslySetInnerHTML`与React中的错误不匹配
- 我如何解决React登录表单状态和浏览器自动填充的问题
- 如何在本地主机上的React应用程序中配置HTTPS
- 如何修复React中的“渲染其他组件时无法更新组件”错误
- 我可以在条件内使用React挂钩吗?
- 将useState与对象一起使用:如何更新
- 如何使用React和Tailwind在代码块中移动
- React,添加到DOM时将焦点放在React中的一个项目上
- 反应,在doubleclick上编辑文本