通往全栈工程师的捷径 —— react

腾讯Bugly特约做者: 左明javascript

首先,咱们来看看 React 在世界范围的热度趋势,下图是关键词“房价”和 “React” 在 Google Trends 上的搜索量对比,蓝色的是 React,红色的是房价,很明显,人类对 React 的关注程度已经远远超过了对房价的关注。html

从这些数据中,你们能看出什么?
能够很明显的看出,我在一本正经的扯淡。前端

从2014年到如今,React、jQuery和 Angular 的热度趋势对比,能够很明显的看到(上图),React 在全球的热度趋势增加很是快。java

上图是 React 在国内的百度搜索指数,是拿 React 和 Nodejs 作了个对比,能够看出 React 的关注度也已经逼近 nodejs。node

虽然在关注总量上 React 还远不及 jQuery 和 Angular 等等,但它的增加幅度超乎你想象,你知道这意味着什么吗?这意味着关注 React,你就比大多数人走在了业界的前沿! react

那么React究竟是什么鬼?git

引用官网的简介,"一个用来构建用户界面的javascript库"。程序员

React 起源于 Facebook 的内部项目,由于 FB 对市场上全部 JavaScript MVC 框架,都不满意,就决定本身写一套,用来架设 Instagram 的网站。作出来之后,发现这套东西很好用,就在2013年5月开源了。github

因为 React 的设计思想极其独特,属于革命性创新,性能出众,代码逻辑却很是简单。因此,愈来愈多的人开始关注和使用,认为它多是未来 Web 开发的主流工具。web

和 Backbone、Angular 等 MV* 框架不同,它只处理 View 逻辑 ,它只处理 View 逻辑,它只处理 View 逻辑。因此若是你喜欢它,你能够很容易的将它接入到现有工程中,而后用 React 重写 HTML 部分便可,不用修改逻辑。

近几年 web 领域的技术革新很是迅速,React也是一项新技术…话说React出来也已经2年了,其实并不算什么新技术了,只是在国内尚未普及开,这篇文章的目的也是帮助你们更快的理解 react 和认识 react 能给咱们带来的价值。

React 这么火,那么它到底有什么牛逼的地方?

上图是2015年年初的数据

这是 Facebook 的好友动态页面,也是 Facebook 访问量最大的页面没有之一,经过 Chrome React 插件能够看到这个页面确实是用 React 实现的。 (有同事问我为何关注柳岩,我说由于我是柳岩的球迷啊)

前面给你们来了一波前戏,相信你们已经有点火烧眉毛了,那么,进入正题: 首先,先跟你们描述下 React 最特别的部分,听完这部分你们基本就可以在脑海里创建起一个 React 的大体印象。

而后是 React 的核心内容,听完这部分你们待会回去就能够开始写代码而后今天晚上发布上线了。 最后是 React 可以给咱们实际带来的价值,咱们不做无心义的代码重构。

首先,咱们来看JSX——

JSX 使用的是预编译模板,React 提供了一个预编译工具,叫 react-tools,能够经过 npm 命令安装,通常是在开发时期运行,运行后它会启动一个监听程序,实时监听 JSX 源码的修改,而后自动编译为 JS 代码。

你们留意下,render() 方法里的被编译成了 React.createElement(),它这么作,目的就是为了实现虚拟 DOM。

接下来咱们来了解 React 最大的亮点 ———— 虚拟 DOM。

传统 web app 和 DOM 直接交互,由App来控制DOM的构建和渲染、元素属性的读写、事件的注册和销毁等等。 当新产品刚上线的时候,这种作法看起来也挺好。但随着产品功能愈来愈丰富、代码量愈来愈多、开发团队人员愈来愈多 —————

一年后

你的代码可能会变成这样。

固然,合理的代码规划可以避免这类问题,但团队里不免会有擅长屠宰式编程的同窗,分分钟把你代码改的面目全非。

这时,React的虚拟DOM和单项数据流就能很好的解决这个问题。

虚拟DOM则是在DOM的基础上创建了一个抽象层,咱们对数据和状态所作的任何改动,都会被自动且高效的同步到虚拟DOM,最后再批量同步到DOM中。

虚拟DOM会使得App只关心数据和组件的执行结果,中间产生的DOM操做不须要App干预,并且经过虚拟DOM来生成DOM,会有一项很是可观收益-----性能。

全部人都知道DOM慢,渲染一个空的DIV,浏览器须要为这个DIV生成几百个属性,而虚拟DOM只有6个,因此减小没必要要的重排重绘以及DOM读写可以对页面渲染性能有大幅提高。

那么咱们来看看虚拟DOM是怎么作的:React会在内存中维护一个虚拟DOM树,当咱们对这个树进行读或写的时候,其实是对虚拟DOM进行的。当数据变化时,而后React会自动更新虚拟DOM,而后拿新的虚拟DOM和旧的虚拟DOM进行对比,找到有变动的部分,得出一个Patch,而后将这个Patch放到一个队列里,最终批量更新这些Patch到DOM中。

这样的机制能够保证即使是根节点数据的变化,最终表如今DOM上的修改也只是受这个数据影响的部分,能够保证很是高效的渲染。

但这样也是有必定的缺陷的----首次渲染大量DOM时由于多了一层虚拟DOM的计算,会比innerHTML插入方式慢,因此使用时须要确保不要一次性渲染大量DOM。

几个UI组件的渲染性能对比

http://mathieuancelin.github.io/js-repaint-perfs/

一个最基本的 React 组件由数据和JSX两个主要部分构成,咱们先来看看数据。

这是一个简单单完整的React组件【类】,细节你们先不用太在乎细节,了解机制就能够。

props 主要做用是提供数据来源,能够简单的理解为 props 就是构造函数的参数。 state 惟一的做用是控制组件的表现,用来存放会随着交互变化状态,好比开关状态等。

JSX 作的事情就是根据 state 和 props 中的值,结合一些视图层面的逻辑,输出对应的 DOM 结构。

前面咱们知道了一个简单的组件的构成,但单个的组件确定不能知足实际需求,咱们须要作的是将这些独立的组件进行组装,同时找出共性的部分进行复用。

好比这样一个场景

咱们以这样一个界面为例,能够看出,里面的 <Pub/> <Article/> 都是最细粒度的组件,是能够复用的。 首先,咱们来看下Article的代码——

这个就是咱们分解出来的 Article 组件,它须要2个属性,article对象和showImage。article对象包含图片、地址、标题、描述信息,showImage是一个布尔类型,用来判断是否须要显示成一个图片。

这个组件自己的实现能够很简单也能够很复杂,但使用者可不关心你的内部实现,使用者关心的是组件须要什么参数就能够了。

外国人的组件化思想比咱们国内的普及程度高不少,不仅局限于软件开发,包括实体行业的咖啡机、加油站、 儿童摇摇车都有这种设计思想在里面。

但愿你们在设计模块的时候,也尽量将组件逻辑对外透明,来减小维护成本。

你们留意一下标虚线的部分,这里复用了 Article 组件。这时的 Article 组件看起来就是一个普通的标签而已,简单吧。

这个是热问组件,也复用了 Article 组件。这就是 React 如丝般顺滑的组件复合。

这个,叫作竹笕,是中日传统禅文化中常见的庭院装饰品,它的构造可简单可复杂,但原理很简单,好比这个竹笕,水从竹笕顶部入口流入内部,并按照固定的顺序从上向下依次流入各个小竹筒,而后驱动水轮转动。对于强迫症患者来讲,观赏竹笕的绝对是一种很享受的过程的最爱,你会发现这些小玩意居然能这么流畅的协调起来,好神奇。

若是竹笕是一个组件的话,那么水就是组件的数据流。

在React中,数据流是自上而下单向的从父节点传递到子节点,因此组件是简单且容易把握的,他们只须要从父节点提供的props中获取数据并渲染便可。若是顶层组件的某个prop改变了,React会递归地向下遍历整棵组件数,从新渲染全部使用这个属性的组件。

这个是前面看到的 Article 题组件,拥有一个叫作 articles 的属性。

在组件内部,能够经过this.props来访问props,props是组件惟一的数据来源,<span style="color: #ff0000;">对于组件来讲</span>:

<span style="color: #ff0000;"> props永远是只读的。</span>

组件的属性类型若是不进行声明和验证,那么极可能使用者传给你的属性值或者类型是无效的,那会致使一些意料以外的故障。好在React已经为咱们提供了一套很是简单好用的属性校验机制——

React有一个PropTypes属性校验工具,通过简单的配置便可。当使用者传入的参数不知足校验规则时,React会给出很是详细的警告,定位问题不要太容易。

PropTypes包含的校验类型包括基本类型、数组、对象、实例、枚举——

以及对象类型的深刻验证等等。若是内置的验证类型不知足需求,还能够经过自定义规则来验证。 若是某个属性是必须的,在类型后面加上 .isRequired 便可。

React的一大创新,就是把每个组件都当作是一个状态机,组件内部经过state来维护组件状态的变化,这也是state惟一的做用。

state通常和事件一块儿使用,咱们先看state,而后看看state和事件怎样结合。

这是一个简单的开关组件,开关状态会以文字的形式表如今按钮的文本上。

首先看render方法,返回了一个button元素,给button注册了一个事件用来处理点击事件,在点击事件中对state的on字段取反,并执行 this.setState() 方法设置on字段的新值。一个开关组件就完成了。

组件渲染完成后,必须有UI事件的支持才能正常工做。

React经过将事件处理器绑定到组件上来处理事件。

React事件本质上和原生JS同样,鼠标事件用来处理点击操做,表单事件用于表单元素变化等,Rreact事件的命名、行为和原生JS差很少,不同的地方是React事件名区分大小写。

好比这段代码中,Article组件的section节点注册了一个onClick事件,点击后弹出alert。

有时候,事件的处理器须要由组件的使用者来提供,这时能够经过props将事件处理器传进来。

这个是刚才那个Article组件的使用者,它提供给Article组件的props中包含了一个onClick属性,这个onClick指向这个组件自身的一个事件处理器,这样就实现了在组件外部处理事件回调。

这是一个React组件实现组件可交互所需的流程,render()输出虚拟DOM,虚拟DOM转为DOM,再在DOM上注册事件,事件触发setState()修改数据,在每次调用setState方法时,React会自动执行render方法来更新虚拟DOM,若是组件已经被渲染,那么还会更新到DOM中去。

这些是React目前支持的事件列表。

React的组件拥有一套清晰完整并且很是容易理解的生命周期机制,大致能够分为三个过程:初始化、更新和销毁,在组件生命周期中,随着组件的props或者state发生改变,它的虚拟DOM和DOM表现也将有相应的变化。

首先是初始化过程,这里会着重讲,须要充分理解。

组件类在声明时,会先调用 getDefaultProps() 方法来获取默认props值,这个方法会且只会在声明组件类时调用一次,这一点须要注意,它返回的默认props由全部实例共享。

在组件被实例化以前,会先调用一次实例方法 getInitialState() 方法,用于获取这个组件的初始state。

实例化以后就是渲染,componentWillMount方法会在生成虚拟DOM以前被调用,你能够在这里对组件的渲染作一些准备工做,好比计算目标容器尺寸而后修改组件自身的尺寸以适应目标容器等等。

接下来就是渲染工做,在这里你会建立一个虚拟DOM用来表示组件的结构。对于一个组件来讲,render 是惟一一个必须的方法。render方法须要知足这几点:

  1. 只能经过 this.props 或 this.state 访问数据

  2. 只能出现一个顶级组件

  3. 能够返回 null、false 或任何 React 组件

  4. 不能对 props、state 或 DOM 进行修改

须要注意的是,render 方法返回的是虚拟DOM。

渲染完成之后,咱们可能须要对DOM作一些操做,好比截屏、上报日志、或者初始化iScroll等第三方非React插件,能够在 componentDidMount() 方法中作这些事情。固然,你也能够在这个方法里经过 this.getDOMNode() 方法取得最终生成DOM节点,而后对DOM节点作爱作的事情,但须要注意作好安全措施,不要缓存已经生成的DOM节点,由于这些DOM节点随时可能被替换掉,因此应该在每次用的时候去读取。

组件被初始化完成后,它的状态会随着用户的操做、时间的推移、数据更新而产生变化,变化的过程是组件声明周期的另外一部分 ——

更新过程。

当组件已经被实例化后,使用者调用 setProps() 方法修改组件的数据时,组件的 componentWillReceiveProps() 方法会被调用,在这里,你能够对外部传入的数据进行一些预处理,好比从props中读取数据写入state。

默认状况下,组件在 setState() 以后,React会遍历这个组件的全部子组件,进行“灌水”,将props从上到下一层一层传下去,并逐个执行更新操做,虽然React内部已经进行过不少的优化,这个过程并不会花费多少时间,可是程序员里永远不缺少长期性能饥渴的同窗,不用担忧,React有一个可以解决你性能饥渴的办法——shouldComponentUpdate()——有时候,props发生了变化,但组件和子组件并不会由于这个props的变化而发生变化,打个比方,你有一个表单组件,你想要修改表单的name,同时你可以确信这个name不会对组件的渲染产生任何影响,那么你能够直接在这个方法里return false来终止后续行为。这样就可以避免无效的虚拟DOM对比了,对性能会有明显提高。

若是这个时候有同窗仍然饥渴难耐,那么你能够尝试不可变数据结构(用过mongodb的同窗应该懂)。

组件在更新前,React会执行componentWillUpdate() 方法,这个方法相似于前面看到的 componentWillMount()方法,惟一不一样的地方只是这个方法在执行的时候组件是已经渲染过的。须要注意的是,不能够在这个方法中修改props或state,若是要修改,应当在 componentWillReceiveProps() 中修改。

而后是渲染,React会拿此次返回的虚拟DOM和缓存中的虚拟DOM进行对比,找出【最小修改点】,而后替换。

更新完成后,React会调用组件的componentDidUpdate 方法,这个方法相似于前面 componentDidMount 方法,你仍然能够在这里能够经过 this.getDOMNode() 方法取得最终的DOM节点。

香港电影结尾常常看到一个剧情,就是英雄战胜了坏人,而后警察出来擦屁股——

componentWillUnmount 除了擦屁股什么也作不了。

你能够在这个方法中销毁非React组件注册的事件、插入的节点,或者一些定时器之类。这个过程可能容易出错,好比绑定了事件却没销毁,这个React可帮不了你,你本身约的炮,含着泪也要打完。

下面咱们来看看React怎样结合nodejs实现服务端渲染。

服务端渲染有多快我就很少说了。

由于有虚拟DOM的存在,React能够很容易的将虚拟DOM转换为字符串,这便使咱们能够只写一份UI代码,同时运行在node里和和浏览器里。
<div class="km_insert_code">
<pre><span class="keyword">var</span> html = React.renderToString(elem);</pre>
</div>

在node里将react组件HTML渲染为HTML,一句代码便可。

不过围绕这个renderToString咱们还要作一些准备工做:

  1. 从后台server或数据库等来源拉取数据

  2. 调用React.renderToString()方法来生成HTML

  3. 最后发送HTML和数据给浏览器

代码就不贴了,你们自行脑补。

须要注意的是这里的JSON字符串中可能出现</script>结尾标签或HTML注释,可能会致使语法错误,这里须要进行转义。

页面的示例代码原本打算用你们更熟悉的HTML,但发现代码量太多了,因此换成了jade代码,没用过jade的同窗也顺便了解一下,我也顺便给jade打个广告。 这个页面作了这几件事:

  1. 将前面在action里生成的HTML写到#container元素里

  2. 引入必须的JS文件

  3. 获取action提供的数据

  4. 渲染组件

这就是React的服务端渲染,组件的代码先后端均可以复用。

是否是感受React挺牛逼的?还没完!

React可以用一套代码同时运行在浏览器和node里,并且可以以原生App的姿式运行在iOS和Android系统中,即拥有了web迭代迅速的特性,又拥有原生App的体验。

这个姿式叫作 React-Native。

这是React和React-Native在github上的数据,能够看出React-Native也是至关热门——由于React-Native可以使React的价值最大化,这个价值是什么呢——对业务来讲,意味着不须要为了作终端版本就招聘和前端等量人力的终端开发,同时意味着咱们成为全栈工程师有了一个捷径。

了解iOS开发的同窗都知道,水果公司对应用上架的审核效率实在让人无力吐槽,不少团队上一个版本还没审核结束,下一个版本就已经作好了。而React-Native支持从网络拉取JS,这样iOS应用也可以像web同样实现快速迭代了。

上图就是react-native的调试过程,以 iOS 为例

  1. 启动 xcode build

  2. 在模拟器中按下 Command + D 打开菜单,选择 Debug in Chrome

  3. 在 Chrome dev tools 中调试

固然,react 并非完美的,在实际使用时你也会发现她的一些缺点,好比:

(若是只是作安卓 app 开发,那么“苹果两件套+开发者证书”不是必须的,在windows下面开发便可。)

最后,你们在使用 react 开发时,可能会须要安装React developer tools

最后是一点参考资料

书山有路勤为径,react 即是那通往『全栈工程师』的捷径。


腾讯Bugly简介

Bugly是腾讯内部产品质量监控平台的外发版本,其主要功能是App发布之后,对用户侧发生的Crash以及卡顿现象进行监控并上报,让开发同窗能够第一时间了解到App的质量状况,及时机型修改。目前腾讯内部全部的产品,均在使用其进行线上产品的崩溃监控。

相关文章
相关标签/搜索