React服务端渲染(总结)


Posted in Javascript onJuly 01, 2017

一、前言

为什么需要服务端渲染?什么情况下进行服务端渲染?笔者认为,当我们要求渲染时间尽量快、页面响应速度快时(优点),才会采用服务器渲染,并且应该“按需”对页面进行渲染 ——“首次加载/首屏”。即服务端渲染的优势在于:由中间层( node端 )为客户端请求初始数据、并由node渲染页面。那客户端渲染和服务端渲染有什么差别?服务端渲染究竟快在哪里呢?

二、原因与思路

客户端渲染路线:1. 请求一个html -> 2. 服务端返回一个html -> 3. 浏览器下载html里面的js/css文件 -> 4. 等待js文件下载完成 -> 5. 等待js加载并初始化完成 -> 6. js代码终于可以运行,由js代码向后端请求数据( ajax/fetch ) -> 7. 等待后端数据返回 -> 8. react-dom( 客户端 )从无到完整地,把数据渲染为响应页面

服务端渲染路线:2. 请求一个html -> 2. 服务端请求数据( 内网请求快 ) -> 3. 服务器初始渲染(服务端性能好,较快) -> 4. 服务端返回已经有正确内容的页面 -> 5. 客户端请求js/css文件 -> 6. 等待js文件下载完成 -> 7. 等待js加载并初始化完成 -> 8. react-dom( 客户端 )把剩下一部分渲染完成( 内容小,渲染快 )

说明:对同一个组件,服务端渲染“可视的”一部分( render/componentWillMount部分代码  ),为确保组件有完善的生命周期及事件处理,客户端需要再次渲染。即:服务端渲染,实际上也是需要客户端进行 再次地、但开销很小的二次渲染。

时间耗时比较:

1. 数据请求:由服务端请求数据而不是客户端请求数据,这是“快”的一个主要原因。服务端在内网进行请求,数据响应速度快。客户端在不同网络环境进行数据请求,且外网http请求开销大,导致时间差(主要原因)。

2. 步骤:服务端是先请求数据然后渲染“可视”部分,而客户端是等待js代码下载、加载完成再请求数据、渲染。即:服务端渲染不用等待js代码下载完成再请求数据,并会返回一个已经有内容的页面。

3. 渲染性能:服务端性能比客户端高,渲染速度快( 猜测,该项数据不详 )。

4. 渲染内容:服务端渲染会把”可视“部分先渲染,然后交给客户端再作部分渲染。而客户端渲染,则是从无到有,需要经历完整的渲染步骤。

React服务端渲染(总结)

三、注意事项与问题

0. 项目依赖什么?答:node端:express、react-dom/server、webpack。前端:React、mobx(一个更好的redux)、React-router、webpack

1. 前端/node端共用那部分代码?答:node端/前端有各自的入口文件,server.js/client.js,通过react-router的路由配置文件routes.js作中间层

// routes.js
module.exports = (
  <Route path="/" component={ IComponent } >
    <Route path="/todo" component={ AComponent }>
    </Route>
  </Route>
)

2. 代码是由前后端共享,那如何分平台地操作不同代码?答:通过webpack。对共享代码,进行不同平台的,webpack(babel)编译,通过在webpack.config.js中加入

// webpack.client.config.js
plugins: [
   new webpack.DefinePlugin({
     '__isServer__': false,
     '__isClient__': true
   })
 ]
// webpack.server.config.js
plugins: [
   new webpack.DefinePlugin({
     '__isServer__': true,
     '__isClient__': false
   })
 ]
// xxx.js
if( __isServer__ ) {
  ...
}else { ... }

React服务端渲染(总结)

4. 组件的生命周期是如何的呢?答:componentWillMount( node端 ) -> render( node端 ) -> 客户端生命周期和以前一样

5. 拉取数据后如何处理呢?答:先在node端根据数据渲染好,再把数据随页面返回至前端,再由React根据数据进行渲染校对( 若前后端渲染结果不一致将报错 )。应该在componentWillMount让组件进行本地的数据同步

// 组件.js
componentWillMount() {
  if( __isClient__ ) {
     this.todoStore.todos = window.initTodos; 
  }
}  
// node端返回
`
<!doctype html>
<html lang="utf-8">
    <head>
    <script> window.initTodo = ${...}</script>
    </head>
    <body> ... </body>
    <script src="/static/vendor.js"></script>
    <script src="/static/client.bundle.js"></script>

6. 前端/node端“入口文件”通过webpack构建有什么不同?答:前端是为了解析JSX与es6代码(包括mobx的es6 decorator),node端除了以上,还需要加入babel-plugin-transform-runtime,是为了在node良好地运行es7 async / awatit

7. 如何保证node端能够先请求数据然后再渲染?答:es7的async / await语法

8. 前端的react-router路由与node端路由如何配合?node如何知道该路由是渲染哪个数据呢?答:前端是以前的react-router配置,node端是react-router的match/RouterContext// 共享文件routes.js

const routes = (
  <Route path="/" component={ IComponent } >
    <Route path="/todo" component={ AComponent }>
    </Route>
  </Route>
)
// 前端入口文件client.js
render(
  <Router routes={ routes } history={ browserHistory } />,
  ele
)
// node端入口文件server.js
let app = express();
app.get('/todo', (req, res) => {

  match({ routes: routes, location: req.url }, async (err, redirect, props) => {
     // match会帮我们找到要渲染的组件链,注:上面一行使用了async语法,因此可以在render之前使用await运行拉取数据的代码
     let html = renderToString(<RouterContext {...props} />)
     res.send( indexPage(html) )
  }
}) 
// node端返回   
let indexPage = (html)=>{
  return `
  <!doctype html>
    <html lang="utf-8">
      <head>
        <script>
        </script>
      </head>
      <body>
        <section id="hzpapp" >${html}</section>
      </body>
      <script src="/static/vendor.js"></script>
      <script src="/static/client.bundle.js"></script>
    </html>
}

9. client.js中是否还能继续使用webpack的require.ensure ? 答:可以。但闪白明显,且node端返回html后会有报错,在加载脚本后该错误能忽略。 

10. 若我使用的是mobx,该如何实例化store ? 答:每一个node请求,都应该返回一个新的独立的store实例,而不是每个node请求共用一个store实例(笔者易犯)。

React服务端渲染(总结)

本demo地址( 前端库React+mobx+ReactRouter ):https://github.com/Penggggg/react-ssr

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
html读出文本文件内容
Jan 22 Javascript
极酷的javascirpt,让你随意编辑任何网页
Feb 25 Javascript
使用javascript实现雪花飘落的效果
Jan 13 Javascript
Node.js 学习笔记之简介、安装及配置
Mar 03 Javascript
详谈LABJS按需动态加载js文件
May 07 Javascript
基于BootStrap环境写jQuery tabs插件
Jul 12 Javascript
AngularJS基础 ng-include 指令示例讲解
Aug 01 Javascript
HTML5基于Tomcat 7.0实现WebSocket连接并实现简单的实时聊天
Oct 31 Javascript
Vue.js实战之使用Vuex + axios发送请求详解
Apr 04 Javascript
Vue $mount实战之实现消息弹窗组件
Apr 22 Javascript
解决layui的radio属性或别的属性没显示出来的问题
Sep 26 Javascript
Vue实现一种简单的无限循环滚动动画的示例
Jan 10 Vue.js
Express + Node.js实现登录拦截器的实例代码
Jul 01 #Javascript
详解node-ccap模块生成captcha验证码
Jul 01 #Javascript
vue元素实现动画过渡效果
Jul 01 #Javascript
JavaScript学习总结之正则的元字符和一些简单的应用
Jun 30 #Javascript
node.js + socket.io 实现点对点随机匹配聊天
Jun 30 #Javascript
详解vue中computed 和 watch的异同
Jun 30 #Javascript
JS 组件系列之Bootstrap Table 冻结列功能IE浏览器兼容性问题解决方案
Jun 30 #Javascript
You might like
php Xdebug 调试扩展的安装与使用.
2010/03/13 PHP
解析php做推送服务端实现ios消息推送
2013/07/01 PHP
thinkphp5.0整合phpsocketio完整攻略(绕坑)
2018/10/12 PHP
浅谈PHP各环境下的伪静态配置
2019/03/13 PHP
深入探讨JavaScript、JQuery屏蔽网页鼠标右键菜单及禁止选择复制
2014/06/10 Javascript
JS中getYear()和getFullYear()区别分析
2014/07/04 Javascript
js中的json对象详细介绍
2014/10/29 Javascript
jQuery对象的length属性用法实例
2014/12/27 Javascript
JavaScript重载函数实例剖析
2016/05/13 Javascript
微信小程序开发实战教程之手势解锁
2016/11/18 Javascript
JS实现的相册图片左右滚动完整实例
2016/11/23 Javascript
JavaScript的变量声明提升问题浅析(Hoisting)
2016/11/30 Javascript
Bootstrap整体框架之CSS12栅格系统
2016/12/15 Javascript
vue实现百度搜索下拉提示功能实例
2017/06/14 Javascript
详解前端路由实现与react-router使用姿势
2017/08/07 Javascript
微信小程序实现签到功能
2018/10/31 Javascript
react项目如何使用iconfont的方法步骤
2019/03/13 Javascript
Javascript和jquery在selenium的使用过程
2019/10/31 jQuery
Vue两个版本的区别和使用方法(更深层次了解)
2020/02/16 Javascript
Vue执行方法,方法获取data值,设置data值,方法传值操作
2020/08/05 Javascript
在vue中嵌入外部网站的实现
2020/11/13 Javascript
详解Python3中的Sequence type的使用
2015/08/01 Python
python 与GO中操作slice,list的方式实例代码
2017/03/20 Python
将python包发布到PyPI和制作whl文件方式
2019/12/25 Python
pytorch中交叉熵损失(nn.CrossEntropyLoss())的计算过程详解
2020/01/02 Python
利用python实现凯撒密码加解密功能
2020/03/31 Python
Python使用re模块验证危险字符
2020/05/21 Python
pandas处理csv文件的方法步骤
2020/10/16 Python
python实现图片,视频人脸识别(opencv版)
2020/11/18 Python
一款基于css3麻将筛子3D翻转特效的实例教程
2014/12/31 HTML / CSS
css3 矩阵的使用详解
2018/03/20 HTML / CSS
JACK & JONES荷兰官网:男士服装和鞋子
2021/03/07 全球购物
介绍一下sql server的安全性
2014/08/10 面试题
捐款倡议书怎么写
2014/05/13 职场文书
应聘教师求职信
2014/07/19 职场文书
车贷收入证明范本
2014/09/14 职场文书