浅谈react前后端同构渲染


Posted in Javascript onSeptember 20, 2017

前后端同构渲染:当客户端请求一个包含React组件页面的时候,服务端首先响应输出这个页面,客户端和服务端有了第一次交互。然后,如果加载组件的过程需要向服务端发出Ajax请求等,客户端和服务端又进行了一次交互,这样,耗时相对较长。前后端同构渲染可以在页面初次加载时把所有地方渲染好一次性响应给客户端

实现方式:保证包管理工具和模块依赖方式一致

包管理工具-npm管理,保证前后端都使用同一个兼容包

模块依赖方式-webpack,保证前后端都采用commonjs的依赖方式,确保代码可以互相依赖

服务端如何渲染:
react全家桶:react、react-router、redux

react 和 reactDOM

reactDOM在这里提供的支持就是reactDOM.render和reactDOM.renderToString函数,其中欠着会在浏览器生成DOM结构,后者会在服务端生成对应的HTML字符串模板。react会在生成的DOM结构上添加一个 data-react-checksum的属性,这是一个 adler32 算法的校验和,用以确保两份模板的一致性。

浅谈react前后端同构渲染 

同时 react 的生命周期在前后端渲染过程中也有所不同。前端渲染的组件拥有完整的生命周期,而后端渲染仅有 componentWillMount 的生命周期。这就意味着,如果我们想进行前后端共同操作的逻辑,如发送数据请求等,可以放在 componentWillMount 的生命周期中;如果想单独处理客户端的逻辑,可以放在其他生命周期,如 componentDidMount 中。

react-router

react-router是react的路由-视图控制库,可以书写边界的声明式路由以控制不同页面的渲染。react-router 本身是一个状态机,根据配置好的路由规则,和输入的 url 路径,通过 match 方法找到对应的组件并进行渲染。

浅谈react前后端同构渲染

这套机制在前端和后端都是相通的,例如在后端,就是下面这样一种实现形式来进行渲染:

app.use(async (ctx, next) => { 
match({ 
location: ctx.originalUrl, 
routes 
}, callback) 
// 渲染完成之后,调用 callback 回调 
// 将 组件 renderToString 返回前端即可 
})

对于前端来说,其实也是处理的上面这些逻辑,不过它被很好的封装在 组件中,我们只需要写好声明式的路由,这一切就可以随着 url 的变化自动发生。

redux

redux是react的数据流管理库,他对服务端渲染的支持很简单,就是单一的store和状态可初始化。后端在进行渲染的时候会构建好单一的store,并将构建好的初始状态通过以json格式,通过全局变量写到生成好的html字符串模板上。
前端通过获取初始状态,生成跟后端徐然完成后一模一样的store,就可以保证前后端渲染数据的一致性,以确保前后端生成的dom结构一致。

优化结果:

开发效率低的问题:同构应用只有一个项目和一套技术栈,只要拥有 react 开发经验,就可以快速投入前端和后端的开发当中;
可维护性差的问题:同构应用可以进行大量的代码公用,包括工具方法、常量、页面组件和 redux 的大部分逻辑等,可重用性大大提高; 首屏性能、SEO 等

处理过程:

客户端发出请求-服务端渲染出组件-返回给客户端

1、在需要同构直出的页面(比如是index.html)放上占位符

<div id="root">@@@</div>
###

以上,当客户端发出首次请求,服务端渲染出组件的html内容放@@@这个位置,然后服务端再渲染出类似这样的js代码段把组件最终渲染到DOM上。也就是说,renderApp方法实际上就是在渲染组件。

2、而为了直接调用renderApp方法,必须让renderApp方法成为window下的方法

window.renderApp = function(){ReactDOM.render(...)}

3、服务端取出index.html,渲染出占位符的内容,替代占位符,并一次性响应给客户端

案例

文件结构

browser.js(在这里把渲染组件的过程赋值给window.renderApp)

bundle.js(把browser.js内容bundle到这里)

Component.js(组件在这里定义)

express.js(服务端)

index.html(同构直出的页面)

package.json

index.html,直出页面放上占位符

<!doctype html>
<html>
<head>
 <meta charset="UTF-8">
 <title>Untitled Document</title>
</head>
<body>

 <div id="root">@@@</div>
 <script src="bundle.js"></script>
 ###
</body>
</html>

Component.js,在这里定义组件

var React = require('react');
var ReactDOM = require('react-dom');

var Component = React.createClass({
 clickHandler: function(){
  alert(this.props.msg)
 },

 render: function(){
  return React.createElement('button', {onClick: this.clickHandler}, this.props.msg)
 }

})

module.exports = Component;

browser.js,把组件渲染过程赋值给window对象

var React = require('react');
var ReactDOM = require('react-dom');

var Component = React.createFactory(require('./Component'));

window.renderApp = function(msg){
 ReactDOM.render(Component({msg: msg}), document.getElementById('root')); 
}

可以通过来触发组件的渲染。稍后,在服务端会把这段代码渲染出来。

express.js,服务端

以上,需要直出的页面有了占位符,定义了组件,并把渲染组件的过程赋值给了window对象,服务端现在要做的工作就是:生成组件的html和渲染组件的js,放到直出页面index.html的占位符位置。

var express = require('express');
var React = require('react');
var ReactDOMServer = require('react-dom/server');
var fs = require('fs');
var Component = React.createFactory(require('./Component'));

//原先把文件读出来
var BUNDLE = fs.readFileSync('./bundle.js',{encoding:'utf8'});
var TEMPLATE = fs.readFileSync('./index.html',{encoding:'utf8'});

var app = express();

function home(req, res){
 var msg = req.params.msg || 'Hello';
 var comp = Component({msg: msg});

 //@@@占位符的地方放组件
 var page = TEMPLATE.replace('@@@', ReactDOMServer.renderToString(comp));

 //###占位符的地方放js
 page = page.replace('###', '<script>renderApp("'+msg+'")</script>')
 res.send(page);
}

//路由
app.get('', home);
app.get('/bundle.js', function(req, res){
 res.send(BUNDLE);
})
app.get('/:msg', home);

app.listen(4000);

package.json中的配置

"scripts": {
"start": "watchify ./browser.js -o ./bundle.js"
},

启动方式
运行:npm start
运行:node express.js
浏览:localhost:4000

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

Javascript 相关文章推荐
找到了一篇jQuery与Prototype并存的冲突的解决方法
Aug 29 Javascript
ExtJs 3.1 XmlTreeLoader Example Error
Feb 09 Javascript
js中有关IE版本检测
Jan 04 Javascript
深入理解JavaScript系列(6):S.O.L.I.D五大原则之单一职责SRP
Jan 15 Javascript
Javascript 面向对象(一)(共有方法,私有方法,特权方法)
May 23 Javascript
jQuery操作基本控件方法实例分析
Dec 31 Javascript
浅析JS动态创建元素【两种方法】
Apr 20 Javascript
jQuery实现可以编辑的表格实例详解【附demo源码下载】
Jul 09 Javascript
angularjs中的$eval方法详解
Apr 24 Javascript
IScroll那些事_当内容不足时下拉刷新的解决方法
Jul 18 Javascript
详解key在Vue列表渲染时究竟起到了什么作用
Apr 20 Javascript
JavaScript基于面向对象实现的无缝滚动轮播示例
Jan 17 Javascript
微信页面弹出键盘后iframe内容变空白的解决方案
Sep 20 #Javascript
微信小程序 页面跳转事件绑定的实例详解
Sep 20 #Javascript
微信小程序 数据绑定及运算的简单实例
Sep 20 #Javascript
Angularjs使用过滤器完成排序功能
Sep 20 #Javascript
微信小程序 swiper组件构建轮播图的实例
Sep 20 #Javascript
node+koa实现数据mock接口的方法
Sep 20 #Javascript
详解angularjs popup-table 弹出框表格指令
Sep 20 #Javascript
You might like
php xfocus防注入资料
2008/04/27 PHP
discuz论坛 用户登录 后台程序代码
2008/11/27 PHP
php mb_substr()函数截取中文字符串应用示例
2014/07/29 PHP
用HTML/JS/PHP方式实现页面延时跳转的简单实例
2016/07/18 PHP
在模板页面的js使用办法
2010/04/01 Javascript
jQuery Lightbox 图片展示插件使用说明
2010/04/25 Javascript
js变换显示图片的实例
2013/04/16 Javascript
js获取GridView中行数据的两种方法 分享
2013/07/13 Javascript
jQuery的animate函数学习记录
2014/08/08 Javascript
JQuery CheckBox(复选框)操作方法汇总
2015/04/15 Javascript
Bootstrap 组件之按钮(二)
2016/05/11 Javascript
JavaScript中的await/async的作用和用法
2016/10/31 Javascript
Ionic3 UI组件之autocomplete详解
2017/06/08 Javascript
webpack 2.x配置reactjs基本开发环境详解
2017/08/08 Javascript
JS实现百度搜索接口及链接功能实例代码
2018/02/02 Javascript
微信小程序图片左右摆动效果详解
2019/07/13 Javascript
node解析修改nginx配置文件操作实例分析
2019/11/06 Javascript
JS实现普通轮播图特效
2020/01/01 Javascript
[50:11]2018DOTA2亚洲邀请赛 4.7总决赛 LGD vs Mineski 第三场
2018/04/09 DOTA
python标准日志模块logging的使用方法
2013/11/01 Python
python基础教程之获取本机ip数据包示例
2014/02/10 Python
Python中使用PDB库调试程序
2015/04/05 Python
利用Python中的pandas库对cdn日志进行分析详解
2017/03/07 Python
从请求到响应过程中django都做了哪些处理
2018/08/01 Python
基于python3 的百度图片下载器的实现代码
2019/11/05 Python
基于python及pytorch中乘法的使用详解
2019/12/27 Python
对Pytorch中Tensor的各种池化操作解析
2020/01/03 Python
Brasty罗马尼亚:购买手表、香水、化妆品、珠宝
2020/04/21 全球购物
Java语言程序设计测试题选择题部分
2014/04/03 面试题
投标单位介绍信
2014/01/09 职场文书
商场拾金不昧表扬信
2014/01/13 职场文书
销售2014年度工作总结
2014/12/08 职场文书
社区活动总结范文
2015/05/07 职场文书
2015年学校办公室主任工作总结
2015/07/20 职场文书
庆祝教师节主题班会
2015/08/17 职场文书
mysql性能优化以及配置连接参数设置
2022/05/06 MySQL