React 同构开发(一)
为什么要做同构
要回答这个问题,首先要问什么是同构。所谓同构,顾名思义就是同一套代码,既可以运行在客户端(浏览器),又可以运行在服务器端(node)。
我们知道,在前端的开发过程中,我们一般都会有一个index.html, 在这个文件中写入页面的基本内容(静态内容),然后引入JavaScript脚本根据用户的操作更改页面的内容(数据)。在性能优化方面,通常我们所说的种种优化措施也都是在这个基础之上进行的。在这个模式下,前端所有的工作似乎都被限制在了这一亩三分地之上。
那么同构给了我们什么样的不同呢?前面说到,在同构模式下,客户端的代码也可以运行在服务器上。换句话说,我们在服务器端就可以将不同的数据组装成页面返回给客户端(浏览器)。这给页面的性能,尤其是首屏性能带来了巨大的提升可能。另外,在SEO等方面,同构也提供了极大的便利。除此以外,在整个开发过程中,同构会极大的降低前后端的沟通成本,后端更加专注于业务模型,前端也可以专注于页面开发,中间的数据转换大可以交给node这一层来实现,省去了很多来回沟通的成本。
基于React的同构开发
说了这么多,如何做同构开发呢?
这还得归功于 React提供的服务端渲染。
ReactDOMServer.renderToString
ReactDOMServer.renderToStaticMarkup
不同于 ReactDom.render将DOM结构渲染到页面, 这两个函数将虚拟DOM在服务端渲染为一段字符串,代表了一段完整的HTML结构,最终以html的形式吐给客户端。
下面看一个简单的例子:
// 定义组件
import React, { Component, PropTypes } from 'react';
class News extends Component {
constructor(props) {
super(props);
}
render() {
var {data} = this.props;
return <div className="item">
<a href={data.url}>{ data.title }</a>
</div>;
}
}
export default News;
我们在客户端,通常通过如下方式渲染这个组件:
// 中间省略了很多其他内容,例如redux等。
let data = {url: 'http://www.taobao.com', title: 'taobao'}
ReactDom.render(<News data={data} />, document.getElementById("container"));
在这个例子中我们写死了数据,通常情况下,我们需要一个异步请求拉取数据,再将数据通过props传递给News组件。这时候的写法就类似于这样:
Ajax.request({params, success: function(data) {
ReactDom.render(<News data={data} />, document.getElementById("container"));
}});
这时候,异步的时间就是用户实际等待的时间。
那么,在同构模式下,我们怎么做呢?
// 假设我们的web服务器使用的是KOA,并且有这样的一个controller
function* newsListController() {
const data = yield this.getNews({params});
const data = {
'data': data
};
this.body = ReactDOMServer.renderToString(News(data));
};
这样的话,我么在服务端就生成了页面的所有静态内容,直接的效果就是减少了因为首屏数据请求导致的用户的等待时间。除此以外,在禁用JavaScript的浏览器中,我们也可以提供足够的数据内容了。
什么原理
其实,react同构开发并没有上面的例子那么简单。上面的例子只是为了说明服务端渲染与客户端渲染的基本不同点。其实,及时已经在服务端渲染好了页面,我们还是要在客户端重新使用ReactDom.render函数在render一次的。因为所谓的服务端渲染,仅仅是渲染静态的页面内容而已,并不做任何的事件绑定。所有的事件绑定都是在客户端进行的。为了避免客户端重复渲染,React提供了一套checksum的机制。所谓checksum,就是React在服务端渲染的时候,会为组件生成相应的校验和(checksum),这样客户端React在处理同一个组件的时候,会复用服务端已生成的初始DOM,增量更新,这就是data-react-checksum的作用。
所以,最终,我们的同构应该是这个样子的:
// server 端
function* newsListController() {
const data = yield this.getNews({params});
const data = {
'data': data
};
let news = ReactDOMServer.renderToString(News(data));
this.body = '<!doctype html>\n\
<html>\
<head>\
<title>react server render</title>\
</head>\
<body><div id="container">' +
news +
'</div><script>var window.__INIT_DATA='+ JSON.stringify(data) +'</script><script src="app.js"></script>\
</body>\
</html>';
};
// 客户端,app.js中
let data = JSON.parse(window.__INIT_DATA__);
ReactDom.render(<News props={data} />, document.getElementById("container"));
小结
最近一直在做同构相关的东西,本文主要讨论react同构开发的基本原理和方式,作为一个引子,其中省去了很多细节问题。关于同构应用开发,其实有很多事情要做,比如node应用的发布、监控、日志管理,react组件是否满足同构要求的自动化检测等。这些事情都是后续要一步一步去做的,到时候也会做一些整理和积累。
React 同构开发(一)的更多相关文章
- React 同构开发(二)
React 同构 所谓同构,简单的说就是客户端的代码可以在服务端运行,好处就是能极大的提升首屏时间,避免白屏,另外同构也给SEO提供了很多便利. React 同构得益于 React 的虚拟 DOM.虚 ...
- 打造高可靠与高性能的React同构解决方案
前言 随着React的兴起, 结合Node直出的性能优势和React的组件化,React同构已然成为趋势之一.享受技术福利的同时,直面技术挑战,在复杂场景下,挑战10倍以上极致的性能优化. 什么是同构 ...
- React同构直出优化总结
收录待用,修改转载已取得腾讯云授权 作者:郭林烁 joeyguo 原文地址 React 的实践从去年在 PC QQ家校群开始,由于 PC 上的网络及环境都相当好,所以在使用时可谓一帆风顺,偶尔遇到点小 ...
- 自制的React同构脚手架
代码地址如下:http://www.demodashi.com/demo/12575.html Web前端世界日新月异变化太快,为了让自己跟上节奏不掉队,总结出了自己的一套React脚手架,方便日后新 ...
- 腾讯新闻构建高性能的 react 同构直出方案
在腾讯新闻抢金达人活动 node 同构直出渲染方案的总结文章中我们整体了解了下同构直出渲染方案在我们项目中的使用.正如我在上篇文章结尾所说的: 应用型技术的难点不是在克服技术问题,而是在于能够不断的结 ...
- [webpack] 配置react+es6开发环境
写在前面 每次开新项目都要重新安装需要的包,简单记录一下. 以下仅包含最简单的功能: 编译react 编译es6 打包src中入口文件index.js至dist webpack配置react+es6开 ...
- React Native开发入门
目录: 一.前言 二.什么是React Native 三.开发环境搭建 四.预备知识 五.最简单的React Native小程序 六.总结 七.参考资料 一.前言 虽然只是简单的了解了一下Reac ...
- React阶段开发总结
这次独立编写了React页面主要是数据切换.点击不同的按钮,Ajax请求不同的后台数据.数据驱动表格内容的显示.使用React组件开发. 开发中获得下面的心得: 1.后台给的地址早一点添加路由(写好数 ...
- React Native开发技术周报2
(1).资讯 1.React Native 0.22_rc版本发布 添加了热自动重载功能 (2).技术文章 1.用 React Native 设计的第一个 iOS 应用 我们想为用户设计一款移动端的应 ...
随机推荐
- 微信小程序自定义事件
案例结构 首先,我还是会以案例的形式向大家讲解(这样也能方便大家更好的理解)简单介绍一下案例项目的内容(以上一章自定义组件的案例为基础)项目名称:component自定义子组件cpt父组件:logs ...
- [转]java设计模式
设计模式(Design Patterns) ——可复用面向对象软件的基础 设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了 ...
- Spring学习(一)——环境准备
以前做的项目都是用.net开发的,以后准备迁移到java平台上,近期正好有个新项目要上马,所以调研下java相关技术.Spring作为java平台下的一个全栈框架, 其简洁优雅的设计和 ...
- SVN检出忽略文件夹文件
具体实现:1.在解决方案目录上点右键2.在乌龟SVN菜单中找到"属性"点开 3.在弹出窗中点 新建--其他 4.在弹出窗中的"属性"中选择"svn: ...
- uni-app开发踩坑记录
大部分问题是我在h5端看不到而在android.iOS平台上暴露出来的,不包含小程序 1.:class="['defaultStyle', dynamicStyle]" 不支持直接 ...
- HTML5 开发APP 第一章
当今天下,移动端基本上是安卓和苹果的天下,基本上没微软什么事,作为微软忠实的支持者,也要顺势而变. 但安卓和IOS 开发是两个完全不同的世界,有没有一种技术,开发完以后可以运行在任意终端呢,答案是有 ...
- 浅谈K8S cni和网络方案
此文已由作者黄扬授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 在早先的k8s版本中,kubelet代码里提供了networkPlugin,networkPlugin是一组接 ...
- hihocoder1634 Puzzle Game
题目链接:(vjudge) 戳我 和上面那个matrix 比较像. 大概题意就是给你一个n*m的矩阵,然后可以选择其中一个数字进行修改(当然也可以不修改),使得矩阵的最大子矩阵尽可能小.最后输出这个值 ...
- VSM Import Cluster功能验证二(导入篇)
三 vsm import cluster 3.1登录vsm web UI 登陆 VSM web UI,https://172.16.34.51/dashboard/vsm/,点击Cluster Man ...
- [Swift]扩展String类:extension String
请参考本博客另一篇技术博文: <[Swift]字符串(String类.NSString类)常用操作> extension String { //获取字符串首字符 var first: St ...