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 动态将数字金额转化为中文大写金额
May 14 Javascript
jquery实现不同大小浏览器使用不同的css样式表的方法
Apr 02 Javascript
javascript实现网站加入收藏功能
Dec 16 Javascript
javascript 小数乘法结果错误的处理方法
Jul 28 Javascript
AngularJS基础 ng-cloak 指令简单示例
Aug 01 Javascript
JS控制静态页面传递参数并获取参数应用
Aug 10 Javascript
javascript DOM的详解及实例代码
Mar 06 Javascript
详解Vue2.0之去掉组件click事件的native修饰
Apr 20 Javascript
vue的无缝滚动组件vue-seamless-scroll实例
Dec 18 Javascript
基于vue cli重构多页面脚手架过程详解
Jan 23 Javascript
你点的 ES6一些小技巧,请查收
Apr 25 Javascript
深入解析ES6中的promise
Nov 08 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不用正则采集速度探究总结
2008/03/24 PHP
php/js获取客户端mac地址的实现代码
2013/07/08 PHP
PHP递归删除多维数组中的某个值
2017/04/17 PHP
PHP实现一个按钮点击上传多个图片操作示例
2020/01/23 PHP
jQuery asp.net 用json格式返回自定义对象
2010/04/07 Javascript
关于JavaScript定义类和对象的几种方式
2010/11/09 Javascript
P3P Header解决Cookie跨域的问题
2013/03/12 Javascript
js 动态为textbox添加下拉框数据源的方法
2014/04/24 Javascript
Juery解决tablesorter中文排序和字符范围的方法
2015/05/06 Javascript
js实现固定显示区域内自动缩放图片的方法
2015/07/18 Javascript
AngularJS框架中的双向数据绑定机制详解【减少需要重复的开发代码量】
2017/01/19 Javascript
nodejs接入阿里大鱼短信验证码的方法
2017/07/10 NodeJs
js用类封装pop弹窗组件
2017/10/08 Javascript
JS实现获取汉字首字母拼音、全拼音及混拼音的方法
2017/11/14 Javascript
vue使用监听实现全选反选功能
2018/07/06 Javascript
JavaScript new对象的四个过程实例浅析
2018/07/31 Javascript
原生JS实现$.param() 函数的方法
2018/08/10 Javascript
javascript设计模式 ? 装饰模式原理与应用实例分析
2020/04/14 Javascript
Python中的下划线详解
2015/06/24 Python
Django接受前端数据的几种方法总结
2016/11/04 Python
python pandas中对Series数据进行轴向连接的实例
2018/06/08 Python
pyspark.sql.DataFrame与pandas.DataFrame之间的相互转换实例
2018/08/02 Python
Python3.0 实现决策树算法的流程
2019/08/08 Python
OpenCV python sklearn随机超参数搜索的实现
2020/01/17 Python
python 装饰器的使用示例
2020/10/10 Python
python中四舍五入的正确打开方式
2021/01/18 Python
美国体育用品商店:Academy Sports + Outdoors
2020/01/04 全球购物
英国网上电器商店:Electricshop
2020/03/15 全球购物
网上商城创业计划书范文
2014/01/31 职场文书
放假通知格式
2015/04/14 职场文书
2015年教师节广播稿
2015/08/19 职场文书
小学一年级班主任工作经验交流材料
2015/11/02 职场文书
乡镇干部学习心得体会
2016/01/23 职场文书
让人感觉高大上的讲话稿怎么写?
2019/07/08 职场文书
成人成长感言如何写?
2019/08/16 职场文书
pytorch 使用半精度模型部署的操作
2021/05/24 Python