第1章 React Native入门
1.1 React Native基本知识
React Native基于React框架而设计,因此,了解React有助于我们更好地理解React Native。
1.1.1 React简介
React是由Facebook推出的前端开发框架,其本身作为MVC模式中的View层来构建UI,也可以以插件的形式应用到Web应用程序的非UI部分构建中,轻松实现与其他JS框架的整合。同时,React通过对虚拟DOM的操作来控制真实的DOM,从而得到页面的局部更新,提高了GPU渲染的性能,而React提出的模块化开发思路也大大提高了代码的可维护性。
React的官方地址是https://github.com/facebook/react。截至2017年4月,React获得了超过62K的star和11K的fork,这说明React得到了技术人员的普遍支持,正是由于这些原因,React.js和Vue.js、Angular.js成为了当今最流行的三大前端框架。
讲到React,就不得不提到组件(Component)的概念,它是React最基础的部分,其功能相当于AngularJS里面的Directive,或是其他JS框架里面的Widgets或Modules。Component可以认为是由HTML、CSS、JavaScript和一些内部数据组合而成的模块,当然Component也可以由很多其他的Component组建而成。不同的Component既可以用纯JavaScript定义,也可以用特有的JavaScript语法JSX创建而成。采用React进行项目开发,能够获得以下优势。
虚拟DOM(Virtual DOM)
传统的Web应用开发,一般都是通过直接操作真实DOM来进行更新操作的,如图1-1所示,但对DOM进行操作通常是比较昂贵的。而React为了尽可能减少对真实DOM的操作,采用了一种强大的方式来更新DOM,代替直接的DOM操作,这就是Virtual DOM,一个轻量级的虚拟DOM。
图1-1 传统的Web应用结构图
虚拟DOM其实是React抽象出一个对象,通过这个Virtual DOM可以更新真实的DOM,由这个Virtual DOM管理真实DOM的更新,如图1-2所示。简单来说,React在每次需要渲染时,会先比较当前DOM内容和待渲染内容的差异,然后再决定如何最优地更新DOM,这个过程被称为reconciliation。
图1-2 React Web应用结构图
除了性能方面的考虑,React引入虚拟DOM更重要的意义在于提供了一种新的开发方式来开发服务端应用、Web应用和手机端应用,如图1-3所示。
图1-3 虚拟DOM结构图
Components组件
虚拟DOM(virtual-dom)不仅带来了简单的UI开发逻辑,同时也带来了组件化开发的思想。所谓组件,即自己封装的具有独立功能的UI部件。React推荐以组件的方式去构成视图,并建议将功能相对独立的模块抽象为组件。例如,Facebook的instagram.com网站都采用React来开发,整个页面就是一个大的组件。
对于React而言,界面被分成不同的组件,每个组件都相对独立。在React开发中,整个界面可以看成是由大小组件构成,每个组件实现自己的逻辑部分即可,彼此独立,如图1-4所示。
图1-4 Components组件示意图
采用组件化开发,往往具有以下特点:
· 可组合(Composeable):一个组件易于和其他组件一起使用,或者嵌套在另一个组件内部。如果在一个组件内部创建了另一个组件,那么父组件拥有它创建的子组件,通过这个特性,一个复杂的UI可以拆分成多个简单的UI组件。
· 可重用(Reusable):每个组件都可以独立出来,被使用在其他相似的UI场景中。
· 可维护(Maintainable):每个小的组件仅仅包含自身的逻辑,更容易被理解和维护。
· 可测试(Testable):每个组件都是独立的,那么对于各个组件分开测试显然要比整个界面容易得多。
数据流(Data Flow)
React采用单向的数据流,即从父节点到子节点的传递,因此更加灵活便捷,也提高了代码的可控性。React单向数据流可以总结为以下流程:Action→Dispatcher→Stroe→View,如图1-5所示。
图1-5 React单向数据流流程图
JSX语法
JSX是React的核心组成部分,React使用JSX来替代常规的JavaScript。它使用XML标记的方式去直接声明界面,目的是通过各种不同的编译器将这些标记编译成标准的JS语言。使用JSX语法后,可以让组件的结构和组件之间的关系看上去更加清晰并且执行效率更高。
1.1.2 React Native简介
React Native(简称RN)是Facebook于2015年4月开源的跨平台移动应用开发框架,是Facebook早先开源的UI框架React在原生移动应用平台的衍生产物,目前支持iOS和Android两大平台。
React Native可以基于目前大热的开源JavaScript库ReactJS来开发iOS和Android移动应用,因为往往只需要开发一套代码就可以满足iOS和Android,正如Facebook说的“Learn once, write anywhere”(仅需学习一次,编写任何平台),由于基于Web技术,React Natie开发起来可以像在浏览器那样随改即所见。
React Native的原理是在JavaScript中使用React抽象操作系统的原生UI组件,代替DOM元素来渲染界面,比如用<View>组件取代<div>,用<Image>组件替代<img>等。React Native主要运行着两个线程:主线程和JavaScript引擎线程,两个线程之间通过批量化的async消息协议来通信。
在UI方面,React Native提供跨平台的类似Flexbox的布局系统,还支持CSS子集。可以用JSX或者普通JavaScript语言,还有CoffeeScript和TypeScript来开发。运用React Native,我们可以使用同一份业务逻辑核心代码来创建原生应用运行在Web端、Android端和iOS端。
React Native相比Web开发或原生开发主要有以下特点:
APP占用体积小
随着业务的迭代,原生APP的体积越来越大,特别是一些老的APP,动辄上百兆,而采用React Native之后,占用体积会大大缩小,而且引入React Native可以实现持续开发。
实现跨平台开发
基于Web技术(HTML5/JavaScript)构建的移动应用速度快,开发周期短,但是体验较差,响应不及时;而使用原生开发,周期长,项目风险不可控。如何提高开发效率,节约人力成本。成为各大公司考虑的问题,而React Native的出现解决了上面的问题,只需要开发一套代码,便可以同时部署到Android和iOS两个移动平台上。
相对成熟的技术
随着Android/iOS的React Native陆续开源,原生提供的组件和API相对丰富,且实现技术基本一致,对于熟悉前端和原生APP开发的人员来说很容易上手。而React Native通过JavaScriptCore将JS转换为原生APP组件进行渲染,其用户体验也可媲美原生APP。
支持动态更新
在原生APP开发中,Android平台可以通过插件化实现热更新。在iOS平台上,热更新策略是严令禁止的(如JSPatch/wax/rollout等技术),而采用React Native技术完全可以满足要求,而又不触碰苹果的底线。
1.1.3 React Native工作原理
使用JavaScript开发移动APP的想法来源于最近几年市场对于移动应用需求的增长,为了快速开发一款可以使用,而体验又不是那么糟糕的APP,很多公司投入大量人力开发跨平台应用。而在这些公司当中,Facebook无疑是做得最好、最成功的。
图1-6 React Native整体框架图
为了更好地理解React Native,我们需要对React Native的工作原理和整体架构有一个了解,如图1-6所示。
如图,React Naitve框架分为3层,分别为:JSX环境层、虚拟DOM层、具体的平台层。这里面最重要的就是虚拟DOM层。
在React中,Virtual DOM就像一个中间虚拟层,位于JavaScript和实际渲染页面之间。对于JS开发者来说,只需要专注于UI层的绘制即可,不需要特别关心具体平台的实现。
虚拟DOM是一个JavaScript的树形结构,主要包含React元素和模块。组件的DOM结构就是映射到对应的虚拟DOM上,React通过渲染虚拟DOM到浏览器,使得用户界面得以显示。React之所以更新界面高效,是因为React的虚拟DOM采用了batching(批处理)和高效的Diff算法,采用Diff算法,可以将时间复杂度从O(n^3)降到O(n),从而提高界面构建的性能。当需要更新组件的时候,会通过Diff算法寻找到要变更的DOM节点,然后通知浏览器更新变化的内容。
虚拟DOM更新视图的过程可以总结为:状态变化→计算差异(Diff算法)→界面渲染。其渲染的原理如图1-7所示。
图1-7 虚拟DOM更新原理图
在界面渲染过程中,React Native针对不同的平台调用原生API去渲染界面,例如iOS平台调用其原生的API去渲染iOS界面,Android平台调用其原生API去渲染Android界面,而不是直接渲染到浏览器的DOM上,这使得React Native不同于基于Web视图的跨平台应用开发方案,因而,采用React Native开发的APP,体验更加接近原生APP。
虚拟DOM和MVVM的对比
虚拟DOM只是MVVM框架的一种实现方案,二者没有好坏之分。在流行的前端框架中,除了React采用虚拟DOM之外,其他MVVM系框架,如Angular、Vue、Avalon,采用的都是数据绑定。
何为数据绑定?简单来说,就是通过观察Directive/Binding对象数据变化,并保留对实际DOM元素的引用,当有数据变化时进行对应的操作。React检查是DOM结构层面的,而MVVM的检查则是数据层面的。MVVM的性能检测也根据检测层面的不同而有所不同:Angular的脏检查使得任何变动都会产生固定的更新的代价;而Vue/Avalon采用的依赖收集,使得在JS和DOM层面都会产生更新。
上面提到两个概念——脏检查和依赖收集。
· 脏检查:scope digest +必要DOM更新
· 依赖收集:重新收集依赖+必要DOM更新
可以看出,Angular效率低的地方在于任何小变动都会引起界面的重绘,但是,当所有数据都变化的时候,Angular并不吃亏。依赖收集在初始化和数据变化的时候都需要重新收集依赖,在数据流比较小的时候几乎可以忽略,但在数据量比较大的时候就会产生一定的消耗。相比之下,React的变动检查则是DOM结构层面的,即使是全新的数据,只要渲染结果没有变化,也不需要重新绘制。
Angular和Vue都提供了重绘的优化机制,即有效地复用实例和DOM元素。在优化的版本中,Angular和Vue采用了track by $index技术后比React的效率更高。
所以在框架选择和技术性能分析的时候,要分清楚初始渲染、小量数据更新、大量数据更新这些不同的场合,以及DOM、脏检查MVVM、数据收集MVVM在不同场合各自的表现和优缺点,具体表现和区别如下。
· 初始渲染阶段:Virtual DOM >脏检查≥依赖收集
· 小量数据更新时:依赖收集>Virtual DOM +优化>脏检查(无法优化)> Virtual DOM无优化
· 大量数据更新时:脏检查+优化≥依赖收集+优化>Virtual DOM(无优化)> MVVM无优化