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 相关文章推荐
javascript编程起步(第五课)
Jan 10 Javascript
Jquery获取复选框被选中值的简单方法
Jul 04 Javascript
javascript实现详细时间提醒信息效果的方法
Mar 11 Javascript
JavaScript中判断函数、变量是否存在
Jun 10 Javascript
JavaScript中三种异步上传文件方式
Mar 06 Javascript
深入浅析Vue组件开发
Nov 25 Javascript
Vue2.0设置全局样式(less/sass和css)
Nov 18 Javascript
vue移动端下拉刷新和上拉加载的实现代码
Sep 08 Javascript
解决layer.open弹出框不能获取input框的值为空的问题
Sep 10 Javascript
基于Element封装一个表格组件tableList的使用方法
Jun 29 Javascript
js实现拖拽与碰撞检测
Sep 18 Javascript
小程序实现左滑删除的效果的实例代码
Oct 19 Javascript
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下过滤html代码的函数 提高程序安全性
2010/03/02 PHP
PHP排序之二维数组的按照字母排序实现代码
2011/08/13 PHP
Zend Framework教程之Bootstrap类用法概述
2016/03/14 PHP
PHP获取当前执行php文件名的代码
2017/03/02 PHP
PHP数组中头部和尾部添加元素的方法(array_unshift,array_push)
2017/04/10 PHP
Nigma vs Liquid BO3 第二场2.14
2021/03/10 DOTA
OfflineSave离线保存代码再次发布使用说明
2007/05/23 Javascript
[原创]用javascript实现检测指定目录是否存在的方法
2008/01/12 Javascript
学习ExtJS(二) Button常用方法
2009/10/07 Javascript
javascript 单例/单体模式(Singleton)
2011/04/07 Javascript
javascript:history.go()和History.back()的区别及应用
2012/11/25 Javascript
正则表达式中特殊符号及正则表达式的几种方法总结(replace,test,search)
2013/11/26 Javascript
使用jQuery重置(reset)表单的方法
2014/05/05 Javascript
JavaScript保存并运算页面中数字类型变量的写法
2015/07/06 Javascript
js实现匹配时换色的输入提示特效代码
2015/08/17 Javascript
JS脚本实现动态给标签控件添加事件的方法
2016/06/02 Javascript
JS实现title标题栏文字不间断滚动显示效果
2016/09/07 Javascript
javascript学习笔记_浅谈基础语法,类型,变量
2016/09/19 Javascript
基于jQuery代码实现圆形菜单展开收缩效果
2017/02/13 Javascript
webpack构建react多页面应用详解
2017/09/15 Javascript
vue.js todolist实现代码
2017/10/29 Javascript
简单说说如何使用vue-router插件的方法
2019/04/08 Javascript
javaScript 实现重复输出给定的字符串的常用方法小结
2020/02/20 Javascript
[04:26]DOTA2上海特锦赛小组赛第二日 TOP10精彩集锦
2016/02/27 DOTA
Python比较文件夹比另一同名文件夹多出的文件并复制出来的方法
2015/03/05 Python
微信跳一跳游戏python脚本
2020/04/01 Python
对python3中的RE(正则表达式)-详细总结
2019/07/23 Python
Python中zipfile压缩文件模块的基本使用教程
2020/06/14 Python
Tensorflow之MNIST CNN实现并保存、加载模型
2020/06/17 Python
党性观念心得体会
2014/09/03 职场文书
班子成员四风问题自我剖析材料
2014/09/29 职场文书
教师评职称工作总结2015
2015/04/20 职场文书
2015夏季作息时间调整通知
2015/04/24 职场文书
爱心捐书倡议书
2015/04/27 职场文书
假期读书倡议书3篇
2019/08/19 职场文书
Django与数据库交互的实现
2021/06/03 Python