详解React服务端渲染从入门到精通
前言
这篇文章是我自己在搭建个人网站的过程中,用到了服务端渲染,看了一些教程,踩了一些坑。想把这个过程分享出来。
我会尽力把每个步骤讲明白,将我理解的全部讲出来。
文中的示例代码来自于这个,也是我正在搭建的个人网站,大家可以一起交流一下。示例代码因为简化,与仓库代码有些许出入
本文中用到的技术
React V16 | React-Router v4 | Redux | Redux-thunk | express
React 服务端渲染
服务端渲染的基本套路就是用户请求过来的时候,在服务端生成一个我们希望看到的网页内容的HTML字符串,返回给浏览器去展示。
浏览器拿到了这个HTML之后,渲染出页面,但是并没有事件交互,这时候浏览器发现HTML中加载了一些js文件(也就是浏览器端渲染的js),就直接去加载。
加载好并执行完以后,事件就会被绑定上了。这时候页面被浏览器端接管了。也就是到了我们熟悉的js渲染页面的过程。
需要实现的目标:
- React组件服务端渲染
- 路由的服务端渲染
- 保证服务端和浏览器的数据唯一
- css的服务端渲染(样式直出)
一般的渲染方式
- 服务端渲染:服务端生成html字符串,发送给浏览器进行渲染。
- 浏览器端渲染:服务端返回空的html文件,内部加载js完全由js与css,由js完成页面的渲染
优点与缺点
服务端渲染解决了首屏加载速度慢以及seo不友好的缺点(Google已经可以检索到浏览器渲染的网页,但不是所有搜索引擎都可以)
但增加了项目的复杂程度,提高维护成本。
如果非必须,尽量不要用服务端渲染
整体思路
需要两个端:服务端、浏览器端(浏览器渲染的部分)
第一: 打包浏览器端代码
第二: 打包服务端代码并启动服务
第三: 用户访问,服务端读取浏览器端打包好的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对象,就是出来多少就
返回给浏览器多少,可以相对减少耗时
路由的服务端渲染
一般场景下,我们的应用不可能只有一个页面,肯定会有路由跳转。我们一般这么用:
import { BrowserRouter, Route } from 'react-router-dom' const App = () => ( <BrowserRouter> {/*...Routes*