React 服务端渲染
服务端渲染的基本套路就是用户请求过来的时候,在服务端生成一个我们希望看到的网页内容的HTML字符串,返回给浏览器去展示。
浏览器拿到了这个HTML之后,渲染出页面,但是并没有事件交互,这时候浏览器发现HTML中加载了一些js文件(也就是浏览器端渲染的js),就直接去加载。
加载好并执行完以后,事件就会被绑定上了。这时候页面被浏览器端接管了。也就是到了我们熟悉的js渲染页面的过程。
需要实现的目标:
- React组件服务端渲染
- 路由的服务端渲染
- 保证服务端和浏览器的数据唯一
- css的服务端渲染(样式直出)
一般的渲染方式
- 服务端渲染:服务端生成html字符串,发送给浏览器进行渲染。
- 浏览器端渲染:服务端返回空的html文件,内部加载js完全由js与css,由js完成页面的渲染
优点与缺点
服务端渲染解决了首屏加载速度慢以及seo不友好的缺点(Google已经可以检索到浏览器渲染的网页,但不是所有搜索引擎都可以)
但增加了项目的复杂程度,提高维护成本。
如果非必须,尽量不要用服务端渲染
//在此我向大家推荐一个前端全栈开发交流圈:619586920 突破技术瓶颈,提升思维能力
整体思路
需要两个端:服务端、浏览器端(浏览器渲染的部分)
第一: 打包浏览器端代码
第二: 打包服务端代码并启动服务
第三: 用户访问,服务端读取浏览器端打包好的index.html文件为字符串,将渲染好的组件、样式、数据塞入html字符串,返回给浏览器
第四: 浏览器直接渲染接收到的html内容,并且加载打包好的浏览器端js文件,进行事件绑定,初始化状态数据,完成同构
React组件的服务端渲染
让我们来看一个最简单的React服务端渲染的过程。
要进行服务端渲染的话那必然得需要一个根组件,来负责生成HTML结构
import React from 'react';
import ReactDOM from 'react-dom';
ReactDOM.hydrate(<Container />, document.getElementById('root'));
当然这里用ReactDOM.render也是可以的,只不过hydrate会尽量复用接收到的服务端返回的内容,
来补充事件绑定和浏览器端其他特有的过程
引入浏览器端需要渲染的根组件,利用react的 renderToString API进行渲染
import { renderToString } from 'react-dom/server'
import Container from '../containers'
// 产生html
const content = renderToString(<Container/>)
const html = `
<html>
<body>${content}</body>
</html>
res.send(html)
在这里,renderToString也可以替换成renderToNodeStream,区别在于前者是同步地产生HTML,也就是如果生成HTML用了1000毫秒,
那么就会在1000毫秒之后才将内容返回给浏览器,显然耗时过长。而后者则是以流的形式,将渲染结果塞给response对象,就是出来多少就
返回给浏览器多少,可以相对减少耗时
//在此我向大家推荐一个前端全栈开发交流圈:619586920 突破技术瓶颈,提升思维能力
路由的服务端渲染
一般场景下,我们的应用不可能只有一